Child projects not showing up in Rally - rally

I have this code:
var projectStore = Ext.create('Rally.data.WsapiDataStore',{
model: 'project',
fetch: ['Name','ObjectID'],
autoLoad: true,
context:{
project: '/project/33086603461',
projectScopeDown: true,
projectScopeUp:false
},
listeners:{
load: function(store,records,success){
console.log('store ',records);
},
scope: this
}
});
When I print the store , it is showing up all the projects instead of just the project with the given object ID and its children. How do I access only the children of the given project?

The project endpoint in WSAPI is a little different in that it does not obey the project/projectScopeUp/projectScopeDown parameters.
You should just add a filter to your store referencing the parent project instead:
var projectStore = Ext.create('Rally.data.WsapiDataStore',{
model: 'project',
fetch: ['Name','ObjectID'],
autoLoad: true,
filters: [{
property: 'Parent',
operator: '=',
value: '/project/33086603461'
}],
listeners:{
load: function(store,records,success){
console.log('store ',records);
},
scope: this
}
});

Related

Rally - Data Context and InlineFilter issue in a RallyGridBoard

Objective :
Trying to build a Rally App to populate "PortFolioItem/features" based upon a Project value selected from a userSearchCombo box.
Methodology:
1. Creating a UserSearchComboBox based upon the 'Project' model.
2. Depending upon the value selected from the combo box,Creating a TreeStore based on the model 'PortfolioItem/Feature'.
The context scoped for the tree Store is based on the value selected from the Project Search Combo Box
app.portfoliotreeStore = Ext.create('Rally.data.wsapi.TreeStoreBuilder').build({
models: modelNames,
autoLoad: true,
enableHierarchy: true,
limit: 'Infinity',
remoteSort: true,
// sorters: app.appSorters,
//fetch: ['Name', 'FormattedID', 'ScheduleState', 'PlanEstimate', 'Owner', 'Project'],
//filters: filters,
// filters: this.getQueryFilter(),
context: {
project: app.selProjectRef,
projectScopeDown: true
}
}).then({
success: this._addGridboard,
failure: this.showErrorNotification,
scope: this
});
In the Add grid Board Method ,created a gridBoard with some plugins
_addGridboard: function(store) {
console.log("Entering _addGridBoard", store);
app.portfoliotreeStore = store;
var modelNames = ['portfolioitem/PPMFeature']
var filters = app.getStoreFilters(app.selProjectName);
console.log("the Grid", app.down('#gridContainer'));
if (app.down('#gridContainer')) {
app.down('#gridContainer').remove('gridBoard');
}
//this.gridBoardConfig = app._getGridBoardConfig(store);
var dataContext = app.getContext().getDataContext();
console.log("DATA CONTEXT ::::", dataContext);
gridStateString = this.statePrefix + "-treegrid";
gridStateId = this.getContext().getScopedStateId(gridStateString);
app.down('#gridContainer').add({
xtype: 'rallygridboard',
itemId: 'gridBoard',
// context: this.getContext(),
modelNames: ['portfolioitem/PPMFeature'],
toggleState: 'grid',
plugins: [
'rallygridboardaddnew', {
ptype: 'rallygridboardinlinefiltercontrol',
inlineFilterButtonConfig: {
//stateful: true,
//stateId: this.getContext().getScopedStateId('filters-1'),
//collapsed: true,
context: this.getContext(),
modelNames: ['portfolioitem/PPMFeature'],
inlineFilterPanelConfig: {
collapsed: true,
quickFilterPanelConfig: {
whiteListFields: [
'Tags',
'Milestones'
],
defaultFields: [
'ArtifactSearch',
'Owner',
'ModelType',
'Milestones'
]
}
}
}
},
{
ptype: 'rallygridboardfieldpicker',
headerPosition: 'left',
modelNames: this._getModelNames()
//stateful: true,
//stateId: this.getContext().getScopedStateId('columns-example')
}
],
stateful: true,
listeners: {
'staterestore': {
fn: this._onGridStateRestore,
single: true
},
'load': {
fn: this._onGridload,
single: true
},
scope: this
},
gridConfig: {
store: store,
storeConfig: {
filters: this.getQueryFilter()
},
columnCfgs: [
'Name',
'Project',
'ScheduleState',
'Owner',
'PlanEstimate'
]
// derivedColumns: this.getDerivedColumns()
},
/*
gridConfig: {
store: store,
storeConfig: {
filters: this.getQueryFilter()
},
columnCfgs: [
'Name',
'Project',
'ScheduleState',
'Owner',
'PlanEstimate'
],
// derivedColumns: this.getDerivedColumns()
},
*/
height: this.getHeight()
});
},
Please Note the following
Not passing any context to the grid component - Reason:: if i pass
"this.getContext" to the Grid, duplicates records are initially loaded into
the grid , once i click on any header to sort the grid,the duplicates disappear.
Issue: catch 22 Situation
The only way for me to get rid of the duplicates is to not pass the context to the GridBoard, However this impacts my Plugin - "rallygridboardinlinefiltercontrol"
if i scroll over my InlinefilterButton , it throws this error
Uncaught TypeError: Cannot read property 'collapsed' of undefined
at constructor._onBeforeShowToolTip (VM556 sdk.js:100)
at constructor.fire (VM556 sdk.js:5)
at constructor.continueFireEvent (VM556 sdk.js:6)
at constructor.fireEventArgs (VM556 sdk.js:6)
at constructor.prototype.fireEventArgs (VM556 sdk.js:18)
at constructor.fireEvent (VM556 sdk.js:6)
at constructor.show (VM556 sdk.js:15)
at constructor.callParent (VM556 sdk.js:2)
at constructor.show (VM556 sdk.js:25)
at constructor.showFromDelay (VM556 sdk.js:25)
And when i Click on it , it Throws this Error
Uncaught TypeError: Cannot read property 'toggleCollapse' of undefined
at constructor._toggleFilterPanel (VM556 sdk.js:100)
at call (VM556 sdk.js:5)
It does not impact my other filters
Ok , I finally found the Issue ... It appears , i need to pass the Context to the grid , but i also need to switch the autoload on the TreeGrid to false , this is because the plugin owns the responsibility of loading the store .... YAY !! Eureka Eureaka I got this ... Can any one sugest any good book on Rally..

How to add custom data in a story board?

Question 1: Is it possible to add custom data (Ex: testcase count : 5) to each card in a story board? If so, how? I couldn't find an example or specific information in documentation.
Question 2: Is it possible to get testcase count (including child story testcases)for a highlevel story in one query?
Please let me know. Here's my code
Ext.define('Rally.Story.View', {
extend: 'Rally.app.App',
launch: function() {
this.add({
xtype: 'rallyfieldvaluecombobox',
fieldLabel: 'Filter by Target Release:',
model: 'UserStory',
field: 'c_TargetRelease',
value: '15.0',
listeners: {
select: this._onSelect,
ready: this._onLoad,
scope: this
}
});
},
_onLoad: function() {
this.add({
xtype: 'rallycardboard',
types: ['User Story'],
attribute: 'ScheduleState',
readOnly: true,
fetch: ['Name', 'TestCases', 'c_StoryType', 'c_TargetRelease', 'PlanEstimate', 'Priority', 'TaskEstimateTotal', 'TaskRemainingTotal'],
context: this.getContext(),
cardConfig: {
editable: false,
showIconsAndHighlightBorder: false,
fields: ['Name', 'c_StoryType', 'c_TargetRelease', 'PlanEstimate', 'c_PriorityBin', 'Parent', 'TestCases', 'TaskEstimateTotal', 'TaskRemainingTotal']
},
storeConfig: {
filters: [
{
property: 'c_StoryType',
value: 'SAGA Feature'
},
{
property: 'c_TargetRelease',
operator: '=',
value: this.down('rallyfieldvaluecombobox').getValue()
}
]
}
});
},
_onSelect: function() {
var board = this.down('rallycardboard');
board.refresh({
storeConfig: {
filters: [
{
property: 'c_StoryType',
value: 'SAGA Feature'
},
{
property: 'c_TargetRelease',
operator: '=',
value: this.down('rallyfieldvaluecombobox').getValue()
}
]
}
});
},
});
Here's a sample card I made that contains the test case count:
You can add a field by simply including an object with some rendering information in it instead of just a simple string in the fields array in the cardConfig:
cardConfig: {
fields: [
'Name', //simple string field to show
{
name: 'TCCount', //field name
hasValue: function() {return true;}, //always show this field
renderTpl: Ext.create('Rally.ui.renderer.template.LabeledFieldTemplate', {
fieldLabel: 'Test Case Count', //the field label
valueTemplate: Ext.create('Ext.XTemplate',
['{[this.getTestCaseCount(values)]}',
{getTestCaseCount: function(data) { return data.Summary.TestCases.Count;}}])
})
},
//additional string fields
'PlanEstimate', 'Parent', 'TestCases', 'TaskEstimateTotal', 'TaskRemainingTotal']
}
This ended up being less straightforward than I thought it might be, but at least it is doable. The key part is using the LabeledFieldTemplate, specifying a field label and a value template to actually render the content.
You'll also notice the little beaker status icon in the footer which is automatically rendered because TestCases was included in the fields list.
As for your second question there is no roll up field on story for the total number of test cases included on child stories.

the experimental hierarchical tree for rally

I see that Hierarchical trees are labeled as experimental on the Rally site (https://help.rallydev.com/apps/2.0rc3/doc/#!/api/Rally.ui.grid.TreeGrid). I wanted to build an app using the hierarchical tree and I had a few questions about the features. Is it possible to filter the tree or no? Also can i add up the totals of the tasks for a given userstory (estimate, todo, actual, etc) and list that total as the userstory value? Is there another way to get a list of the userstories with the tasks in a list beneath it?
A not-treegrid example: this app that uses group and summary features in a grid of tasks in current iteration grouped by workproduct (user story), where Estimate values of individual tasks are summed up. Full code is in this github repo.
launch: function() {
var that = this;
var today = new Date().toISOString();
var stories = Ext.create('Rally.data.wsapi.Store', {
model: 'UserStory',
fetch: ['Tasks'],
filters: [
{
property: 'Iteration.StartDate',
operator: '<=',
value: today
},
{
property: 'Iteration.EndDate',
operator: '>=',
value: today
}
]
});
stories.load().then({
success: this.loadTasks,
scope: this
}).then({
success:function(results) {
that.makeGrid(results);
},
failure: function(){
console.log("oh noes!")
}
});
},
loadTasks: function(stories){
console.log("load tasks",stories)
var promises = [];
_.each(stories, function(story){
var tasks = story.get('Tasks');
if (tasks.Count > 0) {
tasks.store = story.getCollection('Tasks',{fetch:['Name','FormattedID','Estimate','State','Blocked','WorkProduct']});
promises.push(tasks.store.load());
}
});
return Deft.Promise.all(promises);
},
makeGrid: function(results){
var tasks = _.flatten(results);
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 "Estimate Total";
}
},
{
text: 'Name',dataIndex: 'Name',
},
{
text: 'State',dataIndex: 'State',xtype: 'templatecolumn',
tpl: Ext.create('Rally.ui.renderer.template.ScheduleStateTemplate',
{
states: ['Defined', 'In-Progress', 'Completed'],
field: {
name: 'State'
}
})
},
{
text: 'Estimate',dataIndex: 'Estimate',
summaryType: 'sum',
},
{
text: 'WorkProduct',dataIndex: 'WorkProduct',
renderer: function(val, meta, record) {
return '' + record.get('WorkProduct').FormattedID + '';
}
},
]
});
}
Update: If you want to filter the task store include a filter here:
tasks.store = story.getCollection('Tasks',{fetch:['Name','FormattedID','Estimate','State','Blocked','WorkProduct'],filters:{property: 'State',operator: '<',value: 'Completed'}});
A treegrid example: Rally.ui.grid.TreeGrid you referred is still a work in progress. I have not seen a working example of a story hierarchy using a treegrid but it does not mean it's impossible.
When I tested a story hierarchy, child stories did not appear under epic stories, however a story/task hierarchy worked. The filtering worked too. Here is an example:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch:function(){
Ext.create('Rally.data.wsapi.TreeStoreBuilder').build({
models: ['userstory'],
autoLoad: true,
filters:[
{
property: 'Name',
operator: 'contains',
value: 'story'
}
],
enableHierarchy: true
}).then({
success: function(store) {
var grid = Ext.create('Ext.Container', {
items: [{
xtype: 'rallytreegrid',
columnCfgs: [
'Name',
'Owner'
],
store: store
}]
});
that.add(grid);
}
});
}
The screenshot below shows that tasks are nested under a child story as expected,but the child story is not nested under parent. The grid is filtered by Name as expected:

Custom Rally Grid column together with Rally data columns

I am trying to create an app that will display all test sets in the current project and their states in terms of pass/fail totals.
Issues that I face (BTW just started learning ExtJS and Rally SDK yesterday):
- I need to understand how can I use the currently selected project as the one sued in the grid as a filter
- how should a test set pass/fail totals be queried and then displayed in a column in the grid - example : Test set 123 | 45/70
This is an example of an app that uses a project picker and builds a grid of Test Sets by Project. Also see a code example from this post. There is no filed in Web Services API where pass/fail totals are calculated. You will have to iterate over results and calculate totals in your code. I would encourage limiting the number of test case results by some criteria, e.g. CreationDate. In a scenario when test case results are automated the sheer volume of the data can be problematic.
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
var c = Ext.create('Ext.Container', {
items: [
{
xtype: 'rallyprojectpicker',
fieldLabel: 'select project',
listeners:{
change: function(combobox){
if ( this.down('#g')) {
console.log('grid exists');
Ext.getCmp('g').destroy();
console.log('grid deleted');
}
this.onProjectSelected(combobox.getSelectedRecord());
},
scope: this
}
},
],
});
this.add(c);
},
onProjectSelected:function(record){
var project = record.data['_ref'];
console.log('project', project);
var testSetStore = Ext.create('Rally.data.WsapiDataStore', {
model: 'TestSet',
fetch: ['FormattedID','Name', 'Project', 'TestCaseStatus'],
pageSize: 100,
autoLoad: true,
filters: [
{
property: 'Project',
value: project
}
],
listeners: {
load: this.onTestSetsLoaded,
scope: this
}
});
},
onTestSetsLoaded:function(store, data){
var testSets = [];
Ext.Array.each(data, function(testset) {
var ts = {
FormattedID: testset.get('FormattedID'),
_ref: testset.get("_ref"),
Name: testset.get('Name'),
TestCaseStatus: testset.get('TestCaseStatus')
};
testSets.push(ts);
});
this.updateGrid(testSets);
},
updateGrid: function(testSets){
var store = Ext.create('Rally.data.custom.Store', {
data: testSets,
pageSize: 100
});
if (!this.down('#g')) {
this.createGrid(store);
}
else{
this.down('#g').reconfigure(store);
}
},
createGrid: function(store){
console.log("load grid", store);
var g = Ext.create('Rally.ui.grid.Grid', {
id: 'g',
store: store,
columnCfgs: [
{
text: 'Formatted ID', dataIndex: 'FormattedID', xtype: 'templatecolumn',
tpl: Ext.create('Rally.ui.renderer.template.FormattedIDTemplate')
},
{
text: 'Name', dataIndex: 'Name'
},
{
text: 'TestCaseStatus', dataIndex: 'TestCaseStatus'
}
]
});
this.add(g);
},
});
The full html source of this example is available from this repo

Get stories with title containing "Testing" in it via 2.0rc1

Is it possible to get the stories with title containing text "Testing" in it by using filters ?
eg 1. Mobile Testing
2. Testing Smartphone
You may use contains operator:
Ext.create('Rally.data.WsapiDataStore', {
model: 'UserStory',
fetch: ['FormattedID','Name'],
autoLoad: true,
filters:[
{
property: 'Name',
operator: 'contains',
value: "Mobile"
}
],
listeners: {
load: this._onDataLoaded,
scope: this
}
});