The paging tools display, but they do not work. It appears as if the grid is showing 200 items, but there is a total of 315 or so items total and the paging tools do not get me to the other items. I am using a custom model (not one of the Rally standard models) and I cannot find information on how to get paging to work in this scenario.
The app queries all the workspaces in my subscription and creates a list of projects. For each project, I want to know what was the last date a user story was updated in the project and who the proj admins are for the project. The report will be used to identify and retire old projects that are no longer used within the organization. The code needs some refactoring but it works in my subscription apart from an occasional error due to what I believe are timeouts and un-handled exceptions related to them.
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Workspace Projects</title>
<script type="text/javascript" src="https://rally1.rallydev.com/apps/2.1/sdk.js"></script>
<script type="text/javascript">
// ********************************************************************************************
// Rally main function to kick the application off.
// 1. Calls _getProjects to query for projects in the workspace.
// 2. _getProjects calls _getUserStories to identify the last updated user story in
// in the project
// 3. _getUserStories stores the project name and the last updated date of the
// most recently updated story
// 4. _getUserStories calls the _displayGrid function after every call. The
// _displayGrid function will build the grid list based on data queried and stored
// once all the project's user stories have been retrieved.
//
// Data stores used:
// a: Project store is based on Rally's standard Project model
// b: User Stories store is based on Rally's standard User model
// c: MyProjects store is based on a custom model 'UpdatedProjects'
//
// ********************************************************************************************
// ---------------------------------------------------------------------------------------------------------
// Rally functionality begins here...
//---------------------------------------------------------------------------------------------------------
Rally.onReady(function() {
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
// Custom data model defining UpdatedProjects
Ext.define('UpdatedProjects', {
extend: 'Ext.data.Model',
fields: [
{name: 'project', type: 'string' },
{name: 'lastupdatedate', type: 'string' },
{name: 'children', type: 'string' },
{name: 'parent', type: 'string' },
{name: 'workspace', type: 'string' },
{name: 'created', type: 'string' },
{name: 'projadmin1', type: 'string'},
{name: 'projadmin2', type: 'string'},
{name: 'projadmin3', type: 'string'}
]
});
// Ext store to hold updated projects information
this.myProjects = Ext.create('Ext.data.Store', {
model: 'UpdatedProjects',
proxy: {
type: 'memory',
reader: { type: 'array'}
}
});
this.objLoad = 0;
this.projCount = 0;
this.projTotal = 0;
this.projects = new Array();
this.admins = new Array();
this.gridInfo = new Array();
app = this;
// Get the workspaces and for each workspace get the projects
Ext.create('Rally.data.wsapi.Store', {
model: 'Subscription',
fetch: ['Name', 'Workspaces'],
autoLoad: true,
listeners: {
load: function(store, records) {
var subscription = records[0];
console.log('subscription.Name = ' + subscription.get('Name'));
var WorkspacesCollection = subscription.get('Workspaces');
var WorkspaceCount = WorkspacesCollection.Count;
app.setLoading('Retrieving Projects...');
subscription.getCollection('Workspaces').load({
fetch: ['Name', 'State','_ref'],
callback: function(records, operation, success) {
Ext.Array.each(records, function(workspace) {
if (workspace.get('State') === 'Open'){
app.objLoad = app.objLoad + 1;
app._getProjects(workspace.get('_ref'));
}
});
//app._loadGrid(records);
}
});
}
}
});
},
// ---------------------------------------------------------------------------------------------------------
// Function queries for projects associated with the workspace
// ---------------------------------------------------------------------------------------------------------
_getProjects : function (_ref){
// Get user stories for the project
Ext.create('Rally.data.wsapi.Store', {
model: 'Project',
autoLoad: true,
limit: Infinity,
context: {
workspace: _ref,
project: null,
projectScopeDown: true
},
sorters: [
{ property: 'Name',direction: 'ASC' }
],
scope: app,
filters: [
{
property: 'State',
operator: '=',
value: 'Open'
}
],
listeners: {
load: function(store, data, success) {
// For each project get the user stories ordered by most
// recently updated and the admins
// console.log(data);
// Loop through all the projects and get the last updated user story for each
for (i=0; i < data.length; i++) {
app.projects.push(data[i]);
}
app.objLoad = app.objLoad - 1
// console.log(app.objLoad);
if (app.objLoad === 0){
app.setLoading('Retrieving User Stories...');
// Loop through all the projects and get the last updated user story for each
for (i=0; i < app.projects.length; i++) {
app.objLoad = app.objLoad + 1;
projdata = app.projects[i];
parentName = "";
if (projdata.raw.Parent != null){
if (projdata.raw.Parent._refObjectName != null){
parentName = projdata.raw.Parent._refObjectName;
}
}
app._getUserStories(
projdata.raw.WorkSpace_ref,
projdata.raw._ref,
projdata.raw.Name,
projdata.raw.Workspace.Name,
projdata.raw.Children.Count,
projdata.raw.CreationDate.substring(0,10),
parentName);
//app._getAdmins(data[i]);
}
}
}},
fetch: ['Name','State','DirectChildrenCount','Children', 'CreationDate', 'Parent','Editors','Workspace']
});
},
// ---------------------------------------------------------------------------------------------------------
// Function queries for user stories associated with the project
// ---------------------------------------------------------------------------------------------------------
_getUserStories : function (workspaceID,projID, projName, workspaceName,projChildren, projCreated, projParent){
// Get user stories for the project
Ext.create('Rally.data.wsapi.Store', {
model: 'User Story',
limit: 10,
autoLoad: true,
context: {
workspace: workspaceID,
project: projID,
projectScopeDown: false
},
sorters: [
{property: 'LastUpdateDate',direction: 'DESC' }
],
scope: app,
listeners: {
load: function(store, data, success) {
// Initialize last update date for project
var lastUpdateDate = "0000-00-00";
// User stories returned for project?
if (data.length != 0) {
lastUpdateDate = data[0].raw.LastUpdateDate.substring(0,10);
}
var tmpAdmin = '';
app.gridInfo.push([projName,lastUpdateDate,projParent,workspaceName,projChildren,projCreated,tmpAdmin,tmpAdmin,tmpAdmin]);
app.objLoad = app.objLoad - 1;
console.log(app.objLoad);
// if all projects have been processed, then display the grid
if (app.objLoad == 0) {
app.setLoading('Retrieving Users...');
app._getUsers();
/*for (i=0;i<app.projects.length;i++){
projdata = app.projects[i];
app._getAdmins(projdata);
}*/
}
}
},
fetch: ['Name', 'ScheduleState','LastUpdateDate','Project']
});
},
// ---------------------------------------------------------------------------------------------------------
// Start function displays project information in a Grid once all the data is loaded
// ---------------------------------------------------------------------------------------------------------
_displayGrid : function(){
app.setLoading(false);
app.add({
xtype: 'rallygrid',
context: this.getContext(),
autoscroll: true,
showPagingToolbar: true,
showRowActionsColumn: false,
sortableColumns: true,
editable: false,
store: app.myProjects,
columnCfgs: [
{
text: 'Project',
dataIndex: 'project',
width: 300
},
{
text: 'Date Created',
dataIndex: 'created',
width: 150
},
{
text: 'Last Story Updated',
dataIndex: 'lastupdatedate',
width: 150
},
{
text: 'Parent',
dataIndex: 'parent',
width: 200
},
{
text: 'Workspace',
dataIndex: 'workspace',
width: 200
},
{
text: 'Direct Children',
dataIndex: 'children',
width: 100
},
{
text: 'Project Admin 1',
dataIndex: 'projadmin1',
width: 150
},
{
text: 'Project Admin 2',
dataIndex: 'projadmin2',
width: 150
},
{
text: 'Project Admin 3',
dataIndex: 'projadmin3',
flex: 1
}
]
});
},
_getAdmins : function(project) {
var projName = project.get('Name');
app.objLoad = app.objLoad + 1;
project.getCollection('Editors').load({
fetch: ['EmailAddress','UserPermissions'],
filters: [
{
property: 'Disabled',
operator: '=',
value: false
}
],
callback: function(records, operation, success) {
app.objLoad = app.objLoad - 1;
Ext.Array.each(records, function(editor) {
app.objLoad = app.objLoad + 1;
// get the editors permissions
editor.getCollection('UserPermissions').load({
fetch: ['EmailAddress','UserPermissions','TeamMember'],
filters: [
{
property: '_type',
operator: '=',
value: 'projectpermissions'
}
],
callback: function(records, operation, success) {
app.objLoad = app.objLoad - 1;
//console.log("callbacks remaining = " + app.ncallBacks);
Ext.Array.each(records, function(permissions) {
// Only process project permission records
if (permissions.get('_type') === 'projectpermission'){
// Is this permission record is associated with project of interest?
var projInfo = permissions.get('_refObjectName');
var nPos = projInfo.indexOf(projName);
if (nPos != -1) {
nPos = projName.length + 1
var projPermissions = projInfo.substring(nPos);
// if they are admins of the project then log info to the console.
if (projPermissions === "Admin"){
app.admins.push([projName,editor.get('EmailAddress'),editor.get('TeamMember')]);
//console.log(app.admins[app.admins.length-1]);
}
}
}
});
console.log(app.objLoad);
if (app.objLoad === 0) {
/*app.admins.sort(function(a,b){
if(a[0]>b[0]){return 1;}
else if(a[0]<b[0]){return -1;}
else{
if(a[2]>b[2]) return 1;
else if(a[2]<b[2]) return -1;
else return 0;
}
});*/
app._addAdminstoProjs();
app._displayGrid();
}
}
});
});
}
});
},
_addAdminstoProjs : function(){
for (i=0; i<app.admins.length; i++){
for (j=0;j<app.gridInfo.length;j++){
if (app.admins[i][0] === app.gridInfo[j][0]){
if (app.gridInfo[j][6] === ''){
app.gridInfo[j][6] = app.admins[i][1];
}
else if (app.gridInfo[j][7] === ''){
app.gridInfo[j][7] = app.admins[i][1];
}
else if (app.gridInfo[j][8] === ''){
app.gridInfo[j][8] = app.admins[i][1];
}
}
}
}
for (j=0;j<app.gridInfo.length;j++){
// Add project to myProjects store
app.myProjects.add(
{ project: app.gridInfo[j][0],
lastupdatedate: app.gridInfo[j][1],
parent: app.gridInfo[j][2],
workspace: app.gridInfo[j][3],
children: app.gridInfo[j][4],
created: app.gridInfo[j][5],
projadmin1: app.gridInfo[j][6],
projadmin2: app.gridInfo[j][7],
projadmin3: app.gridInfo[j][8],
});
}
},
// ---------------------------------------------------------------------------------------------------------
// Function queries for users associated with the workspace
// ---------------------------------------------------------------------------------------------------------
_getUsers : function(){
// Get users from the workspace
Ext.create('Rally.data.wsapi.Store', {
model: 'User',
autoLoad: true,
scope: app,
limit: Infinity,
fetch: ['EmailAddress','Disabled','UserPermissions'],
filters: [{
property: 'Disabled',
operator: '=',
value: false
}
],
listeners: {
load: function(store, data, success) {
// For each user get their permissions
if (data.length != 0) {
app.setLoading('Retrieving User Permissions...');
app.objLoad = data.length;
// Build an array of project admins
// project, email address, permissions
Ext.Array.each(data, function(user) {
// get the user's permissions
user.getCollection('UserPermissions').load({
fetch: ['EmailAddress','UserPermissions'],
filters: [{
property: '_type',
operator: '=',
value: 'projectpermissions'
}
],
callback: function(records, operation, success) {
app.objLoad = app.objLoad - 1;
Ext.Array.each(records, function(permissions) {
// Only process project permission records
if (permissions.get('_type') === 'projectpermission'){
var projInfo = permissions.get('_refObjectName');
var pType = projInfo.substring(projInfo.length-5);
if (pType === "Admin") {
//console.log(permissions);
var projName = projInfo.substring(0,projInfo.length-6);
// if they are admins of the project then log info to the console.
app.admins.push([projName,user.get('EmailAddress'),permissions.get('TeamMember')]);
}
}
}); //loop
if (app.objLoad === 0) {
app._addAdminstoProjs();
app._displayGrid();
}
} //callback
}); //collection
});//loop
} //if
} //load
} //lis
}); //create
}
});
});
Rally.launchApp('CustomApp', {
name: 'Projects'
});
</script>
<style type="text/css">
</style>
</head>
<body>
</body>
</html>