Display all associated children with wsapi.Store - rally

I've been searching for a way to display all the defects for a project and it's
children in Rally, however I can't seem to find the right way to go about this.
In the constructor it seems there is no parent property, however I've seen this property used in previous versions using wsapiStore. What is the correct way of doing this now?
Here's a look at my code:
config.json:
{
"name": "BasicRallyGrid",
"className": "CustomApp",
"server": "https://rally1.rallydev.com",
"sdk": "2.1",
"javascript": [
"App.js"
],
"css": [
"app.css"
]
}
Call to Store:
this.myStore= Ext.create('Rally.data.wsapi.Store', {
model: 'Defect',
autoLoad: true,
filters: myFilters,
/*filters: Ext.create('Rally.data.wsapi.Filter', {
property: 'Parent',
operator: '=',
value: "SomeParent"
}),
listeners: {
load: function (myStore) {
if (!this.myStore) {
this._createGrid(myStore);
}
},
scope: this
},
fetch: ['FormattedID', 'Name', 'Severity', 'Iteration', 'Project']
});
}
},
My Grid code:
_createGrid: function (myStore) {
this.myGrid = Ext.create('Rally.ui.grid.Grid', {
store: myStore,
columnCfgs: [
'FormattedID', 'Name', 'Severity', 'Iteration', 'Project'
]
});
this.add(this.myGrid);
Any help would be greatly appreciated. Also, as this is my first question here, if I broke some etiquette please let me know so I can avoid it in future posts.
Thank you!

You just need to use project scoping... Check out this guide: https://help.rallydev.com/apps/2.1/doc/#!/guide/data_stores-section-scoping
By default your store will inherit your global scoping, so I would have expected it to just work, but depending on what you're doing you may have to explicitly specify your project scope + up/down.

Related

How to show/hide fields in the admin UI depending on the value from another field with KeystoneJS Next?

I have a Category model set in schema.ts as follows:
Category: list({
fields: {
name: text(),
type: select({
options: [
{ label: "MultipleChoice", value: "MultipleChoice" },
{ label: "Range", value: "Range" },
],
defaultValue: "...",
isRequired: true,
isUnique: true,
ui: { displayMode: "segmented-control" },
}),
from: integer(),
to: integer(),
options: text()
},
})
And this renders these components in the admin UI:
I'd like to show from and to fields only when Range is selected (hiding options field) and the other way around when MultipleChoice is selected. Is there a way to achieve that with Keystone Next?
I also tried another approach splitting the category types in different models and then relate them somehow with the Category model, but I'm not sure how to do so. Something like:
CategoryRange: list({
ui: {
isHidden: true,
},
fields: {
from: integer(),
to: integer(),
},
}),
CategoryMultipleChoice: list({
ui: {
isHidden: true,
},
fields: {
options: text(),
},
})
Conditional fields were supported in Keystone 4. They haven't been brought forward to Keystone 6 (aka. "Next") yet but they're on the roadmap. I'd expect support for them to arrive in the next few months.
Right now, in Keystone 6, probably the best you could do would be to create a custom field type that collected the "type" and "from/to" fields together. This would let you define an interface in the Admin UI that implemented whatever presentation rules you liked.

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.

noEntryText attribute for ComboBoxes won't apply for Custom Fields?

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.

Fetching custom field on portfolio item

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.

Generate items in Ext.dataview.List from hasMany models the MVC way

I have a Blog model with hasMany Posts (and many other fields). Now I want to list these posts in a List-view like that:
[My post #1]
[My post #2]
[My post #3]
As far as the API described, I'm able to pass either a store or a data attribute to Ext.dataview.List. But I was not able to find out how to pass the hasMany records to the list so it will display an item for each of them.
Do I really have to create another store? Isn't it possible to configure my dataview to something like store: 'Blog.posts' or data: 'Blog.posts' or even records: 'Blog.posts'?
Extend the dataview.List to define the itemtpl to loop through the posts
itemTpl: new Ext.XTemplate(
'<tpl for="**posts**" >',
'<div>{TheBlogPost}</div>',
'</tpl>'
)
As #Adam Marshall said, this doesn't work as easy as I imagined.
Sencha autogenerates stores from associations if you know how to access them.
So you simply can switch out the list's store for the autogenerated "substore" when it has loaded.
This approach probably has some problems, e.g. when listpaging plugin is used, but it is quick.
Example:
MODELS
Ext.define('Conversation', {
extend: 'Ext.data.Model',
config: {
fields: [
],
associations:
[
{
type: 'hasMany',
model: "Message",
name: "messages",
associationKey: 'messages'
}
]
}
});
Ext.define('Message' ,
{
extend: "Ext.data.Model",
config: {
idProperty: 'id_message',
fields: [
{ name: 'text', type: 'string' },
{ name: 'date', type: 'string' },
{ name: 'id_message', type: 'int' },
{ name: 'me', type: 'int'} // actually boolean
]
}
}
);
JSON
[
{
"messages": [
{"id_message": 11761, "date": 1378033041, "me": 1, "text": "iiii"},
{"id_message": 11762, "date": 1378044866, "me": 1, "text": "hallo"}
]}
]
CONTROLLER
this.getList().getStore().load(
{
callback: function(records, operation, success) {
//IMPORTANT LINE HERE:
getList().setStore(Ext.getStore(me.getList().baseStore).getAt(0).messages());
},
scope: this
}
);
LIST-VIEW
{
flex: 1,
xtype: 'list',
itemId: 'ConversationList',
data: [],
store: 'ConversationStore',
baseStore: 'ConversationStore',
itemTpl:
' {[app.util.Helpers.DateFromTimestamp(values.date)]}<br><b>{name}</b>' +
' {[app.util.Helpers.fixResidualHtml(values.text)]} </div>' +
},