Rally 我怎样才能制作一个拉力赛应用程序,它可以报告所有者的任务和用户容量?
我正在尝试在Rally中创建自定义计划页面。我想限制分配给用户的任务数量。我可以很容易地创建一个网格,列出每个用户的每个任务,但我不知道如何获得估计小时数的总和 然后,我尝试创建一个自定义报告,但该报告无法合计分配给某个人的任务小时数-即使我将任务标记给某个人并查询该小时数Rally 我怎样才能制作一个拉力赛应用程序,它可以报告所有者的任务和用户容量?,rally,Rally,我正在尝试在Rally中创建自定义计划页面。我想限制分配给用户的任务数量。我可以很容易地创建一个网格,列出每个用户的每个任务,但我不知道如何获得估计小时数的总和 然后,我尝试创建一个自定义报告,但该报告无法合计分配给某个人的任务小时数-即使我将任务标记给某个人并查询该小时数 有什么想法吗?这个定制应用程序通过迭代构建一个任务网格,其中包括UserIterationCapacity数据,特别是TaskEstimates和Capacity的总和 Ext.define('CustomApp', {
有什么想法吗?这个定制应用程序通过迭代构建一个任务网格,其中包括UserIterationCapacity数据,特别是TaskEstimates和Capacity的总和
Ext.define('CustomApp', {
extend: 'Rally.app.TimeboxScopedApp',
componentCls: 'app',
scopeType: 'iteration',
comboboxConfig: {
fieldLabel: 'Select an Iteration:',
labelWidth: 100,
width: 300
},
addContent: function() {
this._makeStore();
},
_makeStore: function(){
Ext.create('Rally.data.WsapiDataStore', {
model: 'Task',
fetch: ['FormattedID','Name','Owner','Estimate'],
pageSize: 100,
autoLoad: true,
filters: [this.getContext().getTimeboxScope().getQueryFilter()],
listeners: {
load: this._onTasksLoaded,
scope: this
}
});
},
onScopeChange: function() {
this._makeStore();
},
_onTasksLoaded: function(store, data){
this.tasks = data;
Ext.create('Rally.data.WsapiDataStore', {
model: 'UserIterationCapacity',
fetch: ['User', 'TaskEstimates', 'Iteration', 'Capacity'],
pageSize: 100,
autoLoad: true,
filters: [this.getContext().getTimeboxScope().getQueryFilter()],
listeners: {
load: this._onAllDataLoaded,
scope: this
}
});
},
_onAllDataLoaded: function(store, data){
var tasks = [];
var users = [];
that = this
if (data.length ===0) {
this._createGrid(); //to refresh grid when no items in iteration
}
Ext.Array.each(this.tasks, function(task) {
var owner = task.get('Owner');
var total;
var cap;
Ext.Array.each(data, function(capacity){
//some tasks have no owner. If this condition is not checked Uncaught TypeError: Cannot read property '_refObjectName' of null
if (owner && capacity.get('User')._refObjectName === owner._refObjectName) {
total = capacity.get('TaskEstimates');
cap = capacity.get('Capacity');
}
});
var t = {
FormattedID: task.get('FormattedID'),
_ref: task.get("_ref"),
Name: task.get('Name'),
Estimate: task.get('Estimate'),
Owner: (owner && owner._refObjectName) || 'None',
Capacity: cap,
TaskEstimates: total
};
that._createGrid(tasks);
tasks.push(t);
});
},
_createGrid: function(stories) {
var myStore = Ext.create('Rally.data.custom.Store', {
data: stories,
pageSize: 100,
});
if (!this.grid) {
this.grid = this.add({
xtype: 'rallygrid',
itemId: 'mygrid',
store: myStore,
columnCfgs: [
{
text: 'Formatted ID', dataIndex: 'FormattedID', xtype: 'templatecolumn',
tpl: Ext.create('Rally.ui.renderer.template.FormattedIDTemplate')
},
{
text: 'Name', dataIndex: 'Name'
},
{
text: 'Estimate', dataIndex: 'Estimate'
},
{
text: 'Owner', dataIndex: 'Owner'
},
{
text: 'User Iteration Capacity', dataIndex: 'Capacity'
},
{
text: 'Task Estimates Total', dataIndex: 'TaskEstimates'
}
]
});
}else{
this.grid.reconfigure(myStore);
}
}
});
我刚刚开始使用Rally,这正是我所追求的。恐怕我对添加自定义应用完全是新手,我已经尝试过了,但没有任何效果(我显然在某个地方做错了什么) 我根据答案创建了以下HTML,不知道是否有人能指出我的错误 我假设我需要创建一个div来包含网格(以及一个元素来包含迭代下拉列表),但是我不知道应该为它们分配什么html id 我的完整html如下所示,我在脚本部分复制了代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>My App</title>
<!--App information-->
<meta name="Name" content="App: My App"/>
<meta name="Version" content="1.0"/>
<meta name="Vendor" content=""/>
<!--Include SDK-->
<script type="text/javascript" src="/apps/1.29/sdk.js"></script>
<!--App code-->
<script type="text/javascript">
function onLoad() {
//Add app code here
Ext.define('CustomApp', {
extend: 'Rally.app.TimeboxScopedApp',
componentCls: 'app',
scopeType: 'iteration',
comboboxConfig: {
fieldLabel: 'Select an Iteration:',
labelWidth: 100,
width: 300
},
addContent: function() {
this._makeStore();
},
_makeStore: function(){
Ext.create('Rally.data.WsapiDataStore', {
model: 'Task',
fetch: ['FormattedID','Name','Owner','Estimate'],
pageSize: 100,
autoLoad: true,
filters: [this.getContext().getTimeboxScope().getQueryFilter()],
listeners: {
load: this._onTasksLoaded,
scope: this
}
});
},
onScopeChange: function() {
this._makeStore();
},
_onTasksLoaded: function(store, data){
this.tasks = data;
Ext.create('Rally.data.WsapiDataStore', {
model: 'UserIterationCapacity',
fetch: ['User', 'TaskEstimates', 'Iteration', 'Capacity'],
pageSize: 100,
autoLoad: true,
filters: [this.getContext().getTimeboxScope().getQueryFilter()],
listeners: {
load: this._onAllDataLoaded,
scope: this
}
});
},
_onAllDataLoaded: function(store, data){
var tasks = [];
var users = [];
that = this
if (data.length ===0) {
this._createGrid(); //to refresh grid when no items in iteration
}
Ext.Array.each(this.tasks, function(task) {
var owner = task.get('Owner');
var total;
var cap;
Ext.Array.each(data, function(capacity){
//some tasks have no owner. If this condition is not checked Uncaught TypeError: Cannot read property '_refObjectName' of null
if (owner && capacity.get('User')._refObjectName === owner._refObjectName) {
total = capacity.get('TaskEstimates');
cap = capacity.get('Capacity');
}
});
var t = {
FormattedID: task.get('FormattedID'),
_ref: task.get("_ref"),
Name: task.get('Name'),
Estimate: task.get('Estimate'),
Owner: (owner && owner._refObjectName) || 'None',
Capacity: cap,
TaskEstimates: total
};
that._createGrid(tasks);
tasks.push(t);
});
},
_createGrid: function(stories) {
var myStore = Ext.create('Rally.data.custom.Store', {
data: stories,
pageSize: 100,
});
if (!this.grid) {
this.grid = this.add({
xtype: 'rallygrid',
itemId: 'mygrid',
store: myStore,
columnCfgs: [
{
text: 'Formatted ID', dataIndex: 'FormattedID', xtype: 'templatecolumn',
tpl: Ext.create('Rally.ui.renderer.template.FormattedIDTemplate')
},
{
text: 'Name', dataIndex: 'Name'
},
{
text: 'Estimate', dataIndex: 'Estimate'
},
{
text: 'Owner', dataIndex: 'Owner'
},
{
text: 'User Iteration Capacity', dataIndex: 'Capacity'
},
{
text: 'Task Estimates Total', dataIndex: 'TaskEstimates'
}
]
});
}else{
this.grid.reconfigure(myStore);
}
}
});
}
rally.addOnLoad(onLoad);
</script>
<!--App styles-->
<style type="text/css">
.myApp {
/* Add app styles here */
}
</style>
</head>
<body class="myApp">
<div id="mygrid"></div>
</body>
</html>
我的应用程序
函数onLoad(){
//在此处添加应用程序代码
Ext.define('CustomApp'{
扩展:“Rally.app.TimeboxScopedApp”,
组件CLS:“应用程序”,
scopeType:'迭代',
comboboxConfig:{
fieldLabel:“选择迭代:”,
标签宽度:100,
宽度:300
},
addContent:function(){
这个;
},
_makeStore:function(){
Ext.create('Rally.data.WsapiDataStore'{
模型:“任务”,
获取:['FormattedID','Name','Owner','Estimate'],
页面大小:100,
自动加载:对,
筛选器:[this.getContext().getTimeboxScope().getQueryFilter()],
听众:{
加载:此。\u onTasksLoaded,
范围:本
}
});
},
onScopeChange:function(){
这个;
},
_onTasksLoaded:函数(存储、数据){
这个任务=数据;
Ext.create('Rally.data.WsapiDataStore'{
模型:“UserIterationCapacity”,
获取:['User','TaskEstimates','Iteration','Capacity'],
页面大小:100,
自动加载:对,
筛选器:[this.getContext().getTimeboxScope().getQueryFilter()],
听众:{
加载:这个。_onaldataloaded,
范围:本
}
});
},
_onAllDataLoaded:函数(存储、数据){
var任务=[];
var用户=[];
那=这
如果(data.length==0){
这是。_createGrid();//在迭代中没有项目时刷新网格
}
Ext.Array.each(this.tasks,function(task){
var owner=task.get('owner');
总风险价值;
var上限;
Ext.Array.each(数据、功能(容量){
//某些任务没有所有者。如果未选中此条件,则未捕获类型错误:无法读取null的属性“\u REOBJECTNAME”
if(owner&&capacity.get('User')。\u-reobjectname==owner.\u-reobjectname){
总计=容量。获取('TaskEstimates');
cap=容量。获取(“容量”);
}
});
变量t={
FormattedID:task.get('FormattedID'),
_ref:task.get(“\u ref”),
名称:task.get('Name'),
估计:task.get('Estimate'),
所有者:(所有者和所有者._REOBJECTNAME)| |“无”,
容量:上限,
估计数:总数
};
创建网格(任务);
任务。推(t);
});
},
_createGrid:函数(故事){
var myStore=Ext.create('Rally.data.custom.Store'{
数据:故事,
页面大小:100,
});
如果(!this.grid){
this.grid=this.add({
xtype:“rallygrid”,
itemId:'mygrid',
商店:myStore,
专栏CFGS:[
{
text:'Formatted ID',dataIndex:'FormattedID',xtype:'templatecolumn',
第三方物流: