I have a few custom fields on my portfolio item such as c_TrafficLightCost. but when I pass it in the fetch, to create my grid, it doesn't create a columns with the value of the custom field.
Here is my code:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
console.log('Our First App woot!');
this._loadData();
},
// Get data from Rally
_loadData: function() {
var myStore = Ext.create('Rally.data.wsapi.Store', {
model: 'portfolioitem/deliverable',
autoLoad: true,
listeners: {
load: function(myStore, myData, success) {
console.log('got data!', myStore, myData, success);
this._loadGrid(myStore);
},
scope: this
},
fetch: ['FormattedID', 'Name', 'c_TrafficLightCost' ]
});
},
// Create and Show a Grid of given stories
_loadGrid: function(myStoryStore) {
var myGrid = Ext.create('Rally.ui.grid.Grid', {
store: myStoryStore,
columnCfgs: [
'FormattedID', 'Name', 'c_TrafficLightCost'
]
});
this.add(myGrid);
console.log('what is this?', this);
console.log(this.c_TrafficLightCost);
}
});
What I want is for the traffic light to be a column in the grid
Can anyone help me?
Thanks.
Best regards Martin
Remove c_ in front of the custom field name. Try TrafficLightCost and see if that does it. I confirmed that the code posted in this git hub repo does not show values for custom fields (the column is empty) when c_ is prepended to the field name. I think this is a defect.
Related
I' m struggling to display leaf node count on individual cards of a feature story board. I' m using Lookback API to query leaf node stories. Below code is not displaying data correctly and its skipping the field for an entire column. Could you please let me know what I 'm doing wrong here or if there's an easy way to do this. I 'm a novice app developer. Thanks in advance!
cardConfig: {
editable: false,
showIconsAndHighlightBorder: false,
fields: [
'Name',
{
name: 'LeafCount', //field name
hasValue: function() {return true;}, //always show this field
renderTpl: Ext.create('Rally.ui.renderer.template.LabeledFieldTemplate', {
fieldLabel: 'Leaf story Count', //the field label
valueTemplate: Ext.create('Ext.XTemplate',
['{[this.getLeafCount(values)]}',
{getLeafCount: function(data) {
var OID = data.ObjectID;
snapshotStore = Ext.create('Rally.data.lookback.SnapshotStore', {
listeners: {
load: function(store, records, success) {
console.log(records.length);
count = records.length;
}
},
autoLoad: true,
useHttpPost: true,
fetch: ['Name', 'FormattedID', 'ObjectID'],
find: {
"_ItemHierarchy": OID,
"_TypeHierarchy": "HierarchicalRequirement",
"Children": null,
"__At": "current"
},
scope: this
});
return count;
// return snapshotStore.totalCount;
}
}])
})
},
//additional string fields
'c_StoryType', 'Project', 'PlanEstimate', 'Parent', 'TaskEstimateTotal', 'TaskRemainingTotal']
},
This isn't working for you because all the data needs to be available when the template is evaluated- there isn't time to do an async store load before rendering the value.
For this specific case can't you just show the built-in LeafStoryCount field on your cards?
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.
I'm currently working with comboboxes and filters to implement an option to select all instances of a desired field. With that said, I know to use the noEntryText attribute to set what originally defaults to "--No Entry--" as "All". However, the changes do not seem to apply when I use this on custom fields provided by my Web Services API (those fields with the "c_" before them).
Strangely enough though, this convention works for other fields that I use that do not have the "c_" before them. So is this a known defect just for custom fields or is there a workaround to this issue?
I filed a defect that replacing noEntryText to a custom value works for rallyfieldvaluecombobox for standard fields, but not custom fields.
If rallyfieldvaluecombobox uses a standard field, e.g. Environment, then no entry can be replaced successfully:
Here is the js file:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
this.add({
xtype: 'rallyfieldvaluecombobox',
itemId: 'aBox',
fieldLabel: 'Filter by filed:',
model: 'defect',
//field: 'c_CustomBox',
field: 'Environment',
noEntryText: 'All',
useNullForNoEntryValue: true,
allowNoEntry: true,
listeners: {
select: this._onSelect,
ready: this._onLoad,
scope: this
}
});
},
_onLoad: function() {
this.add({
xtype: 'rallygrid',
columnCfgs: [
'FormattedID',
'Name',
//'c_CustomBox'
'Environment'
],
context: this.getContext(),
storeConfig: {
model: 'defect',
filters: [this._getStateFilter()]
},
width: 500
});
},
_getStateFilter: function() {
if (!this.down('#aBox').getValue()) {
return 1;
}
else{
return {
//property: 'c_CustomBox',
property: 'Environment',
operator: '=',
value: this.down('#aBox').getValue()
};
}
},
_onSelect: function() {
var grid = this.down('rallygrid'),
store = grid.getStore();
store.clearFilter(true);
store.filter(this._getStateFilter());
}
});
If the same rallyfieldvaluecombobox uses a custom field, then no entry string cannot be replaced:
In both cases the functionality of replacing the filtering behavior works fine.
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:
I have no issues showing the parent for features in my cardboard when the cardboard is only displaying features:
cardConfig: {
xtype: 'rallycard',
listeners: {
fieldclick : function(field, card) {
_loadDetails(card);
}
},
fields: [
'Name',
// 'Parent' - either one of these ways works
{
name: 'Parent',
fetch: ['Parent'],
renderTpl: Ext.create('Ext.XTemplate', 'Parent: {Parent.Name}')
}
]
},
However, when my kanban board is displaying both features and rollups, the parent information does not display on the card. I have tried conditionally setting it, or using a renderer instead of a renderTpl (the renderer was never called) - I cannot find a way to do this correctly in the API docs.
Here is an App.js code where the Theme cards do not show Parent field, but Feature and Initiative cards do:
Ext.define('CustomApp', { extend: 'Rally.app.App', componentCls: 'app',
launch: function() {
var addNewConfig = {
xtype: 'rallyaddnew',
recordTypes: ['PortfolioItem/Feature', 'PortfolioItem/Initiative', 'PortfolioItem/Theme'],
ignoredRequiredFields: ['Name', 'Project'],
showAddWithDetails: false,
};
this.addNew = this.add(addNewConfig);
var myCardConfig = {
xtype: 'rallycard',
fields: ['State','Parent']
}
var cardBoardConfig = {
xtype: 'rallycardboard',
types: ['PortfolioItem/Feature', 'PortfolioItem/Initiative', 'PortfolioItem/Theme'],
attribute: 'InvestmentCategory',
cardConfig: myCardConfig
};
this.cardBoard = this.add(cardBoardConfig);
}
});