<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <!-- Copyright (c) 2012 Rally Software Development Corp. All rights reserved --> <html> <head> <title>Open Stories, Tasks and Defects by Iteration</title> <meta name="Name" content="App: Open Stories, Tasks and Defects by Iteration" /> <meta name="Version" content="2012.11.19" /> <meta name="Vendor" content="Rally Software" /> <script type ="text/javascript" src="/apps/1.32/sdk.js"></script> <script type ="text/javascript"> var iterDropdown; var rallyDataSource; function OpenStoriesTasksAndDefects() { var that = this; var busySpinner; var taskTable, defectTable, storyTable; var abbrev = {'User Story': 'ar', 'Defect': 'df', 'Task': 'tk', 'TestCase': 'tc'}; function indentedItem(content, color) { var indentationDiv = '<div style="margin-left: 20px;">' + content + '</div>'; return indentationDiv; } function ownerIfKnown(arti) { var owner = ""; if (arti.Owner) { if (arti.Owner.DisplayName) { owner = arti.Owner.DisplayName; } else if (arti.Owner.UserName) { owner = arti.Owner.UserName; } } return owner; } function artifactLink(artifactName, artifact) { var artUrl = "__SERVER_URL__/detail/_ABBREV_/_OID_"; artUrl = artUrl.replace('_ABBREV_', abbrev[artifactName]); artUrl = artUrl.replace('_OID_', artifact.ObjectID); var linkText = artifact.FormattedID + " " + artifact.Name; var link = '<a href="_URL_" target="_blank">_TEXT_</a>'; link = link.replace('_URL_', artUrl); link = link.replace('_TEXT_', linkText); return link; } function showStories(stories, contentDiv) { var story, storyLink, storyInfo; var task, taskLink, taskInfo, indentedTask; var defect, defectLink, defectInfo, indentedDefect; var testCase, testCaseLink, tcInfo, indentedTestCase; var tableData = []; var tblConfig; for (var i = 0; i < stories.length; i++) { story = stories[i]; storyLink = artifactLink('User Story', story); storyInfo = { 'itemLink' : '<div style="font-weight: bold;">' + storyLink + '</div>', 'status' : '<b>' + story.ScheduleState + '</b>', 'userName' : ownerIfKnown(story) }; tableData.push(storyInfo); for (var t = 0; t < story.Tasks.length; t++) { task = story.Tasks[t]; taskLink = artifactLink('Task', task); indentedTask = indentedItem(taskLink); taskInfo = { 'itemLink' : indentedTask, 'status' : task.State, 'userName' : ownerIfKnown(task) }; if (task.State != 'Completed' && task.State != 'Accepted') { tableData.push(taskInfo); } } for (var d = 0; d < story.Defects.length; d++) { defect = story.Defects[d]; defectLink = artifactLink('Defect', defect); indentedDefect = indentedItem(defectLink); defectInfo = { 'itemLink' : indentedDefect, 'status' : defect.ScheduleState, 'userName' : ownerIfKnown(defect) }; var schedState = defect.ScheduleState; if (schedState != 'Completed' && schedState != 'Accepted') { tableData.push(defectInfo); } } for (var tc = 0; tc < story.TestCases.length; tc++) { testCase = story.TestCases[tc]; testCaseLink = artifactLink('TestCase', testCase); indentedTestCase = indentedItem(testCaseLink); tcInfo = { 'itemLink' : indentedTestCase, 'status' : testCase.LastVerdict, 'userName' : ownerIfKnown(testCase) }; // consider testing on testCase.LastVerdict != 'Pass' to decide whether to show in table tableData.push(tcInfo); } } tblConfig = { 'columnKeys' : ['itemLink', 'status', 'userName'], 'columnHeaders' : ['Artifact', 'Status', 'Owner' ], 'columnWidths' : ['400px', '100px', '100px' ], 'sortingEnabled' : false }; storyTable = new rally.sdk.ui.Table(tblConfig); storyTable.addRows(tableData); storyTable.display(contentDiv); } function showTasks(tasks, contentDiv) { var tableData = []; var tblConfig; var task, taskLink, taskInfo; for (var t = 0; t < tasks.length; t++) { task = tasks[t]; taskLink = artifactLink('Task', task); taskInfo = { 'taskLink' : taskLink, 'status' : task.State, 'userName' : ownerIfKnown(task) }; tableData.push(taskInfo); } tblConfig = { 'columnKeys' : ['taskLink', 'status', 'userName'], 'columnHeaders' : ['Task', 'Status', 'Owner' ], 'columnWidths' : ['400px', '100px', '100px' ], 'sortingEnabled' : false }; taskTable = new rally.sdk.ui.Table(tblConfig); taskTable.addRows(tableData); taskTable.display(contentDiv); } function showDefects(defects, contentDiv) { var tableData = []; var tblConfig; var defect, defectLink, defectInfo; for (var d = 0; d < defects.length; d++) { defect = defects[d]; defectLink = artifactLink('Defect', defect); defectInfo = { 'defectLink' : defectLink, 'status' : defect.ScheduleState, 'userName' : ownerIfKnown(defect) }; tableData.push(defectInfo); } tblConfig = { 'columnKeys' : ['defectLink', 'status', 'userName'], 'columnHeaders' : ['Defect', 'Status', 'Owner' ], 'columnWidths' : ['400px', '100px', '100px' ], 'sortingEnabled' : false }; defectTable = new rally.sdk.ui.Table(tblConfig); defectTable.addRows(tableData); defectTable.display(contentDiv); } function showResults(results) { document.getElementById("UserNameHeader").innerHTML = "Open Items for __USER_NAME__"; document.getElementById("stories_count").innerHTML = ""; document.getElementById("tasks_count").innerHTML = ""; document.getElementById("defects_count").innerHTML = ""; if(busySpinner) { busySpinner.hide(); busySpinner = null; } var ownedStories = results.stories; document.getElementById("stories_count").innerHTML = "Stories: " + ownedStories.length; if (ownedStories.length > 0) { showStories(ownedStories, "stories"); } var ownedTasks = results.tasks; document.getElementById("tasks_count").innerHTML = "Tasks: " + ownedTasks.length; if (ownedTasks.length > 0) { showTasks(ownedTasks, "tasks"); } var ownedDefects = results.defects; document.getElementById("defects_count").innerHTML = "Defects: " + ownedDefects.length; if (ownedDefects.length > 0) { showDefects(ownedDefects, "defects"); } } that.onIterationSelected = function() { var targetIterationName = iterDropdown.getSelectedName(); var iterCond = '(Iteration.Name = "_ITER_TARGET_")'.replace('_ITER_TARGET_', targetIterationName); var ownerCondition = '(Owner.UserName = "__USER_NAME__")'; var scheduleStateCondition = '((ScheduleState != "Completed") AND (ScheduleState != "Accepted"))'; var taskStateCondition = '(State != "Completed")'; var storyCriteria = '(' + iterCond + ' AND ' + '(' + ownerCondition + ' AND ' + scheduleStateCondition + '))'; var taskCriteria = '(' + iterCond + ' AND ' + '(' + ownerCondition + ' AND ' + taskStateCondition + '))'; var defectCriteria = '(' + iterCond + ' AND ' + '(' + ownerCondition + ' AND ' + scheduleStateCondition + '))'; var queryConfigs = []; queryConfigs[0] = { type : 'hierarchicalrequirement', key : 'stories', fetch: 'ObjectID,FormattedID,Name,ScheduleState,State,' + 'Owner,UserName,DisplayName,Tasks,Defects,TestCases,LastVerdict', query: storyCriteria, order: 'Rank desc' }; queryConfigs[1] = { type : 'task', key : 'tasks', fetch: 'ObjectID,FormattedID,Name,Owner,UserName,DisplayName,State', query: taskCriteria, order: 'FormattedID' }; queryConfigs[2] = { type : 'defect', key : 'defects', fetch: 'ObjectID,FormattedID,Name,Owner,UserName,DisplayName,ScheduleState', query: defectCriteria, order: 'FormattedID' }; busySpinner = new rally.sdk.ui.basic.Wait({}); busySpinner.display("wait"); if(storyTable) { storyTable.destroy(); storyTable = null; } if(taskTable) { taskTable.destroy(); taskTable = null; } if(defectTable) { defectTable.destroy(); defectTable = null; } rallyDataSource.findAll(queryConfigs, showResults); }; } </script> <style type="text/css"> body { font-size: 10pt; } .count { margin-left: 10px; margin-bottom: 5px; } #iterations { float: left; } #wait { float: left; height: 16px; width: 24px; } h4#UserNameHeader { clear: both; padding-top: 15px } </style> <script type="text/javascript"> function onLoad() { var appCustom = new OpenStoriesTasksAndDefects(); rallyDataSource = new rally.sdk.data.RallyDataSource('__WORKSPACE_OID__', '__PROJECT_OID__', '__PROJECT_SCOPING_UP__', '__PROJECT_SCOPING_DOWN__'); var iterConfig = {label: "Select Iteration "}; iterDropdown = new rally.sdk.ui.IterationDropdown(iterConfig, rallyDataSource); iterDropdown.display("iterations", appCustom.onIterationSelected); } rally.addOnLoad(onLoad); </script> </head> <body> <div id="iterations"></div> <div id="wait"></div> <h4 id="UserNameHeader">Open Items</h4> <div class="count" id="stories_count"></div> <div id="stories"></div> <br><br> <div class="count" id="tasks_count"></div> <div id="tasks"></div> <br><br> <div class="count" id="defects_count"></div> <div id="defects"></div> </body> </html>