This is the raw programming, can this be modified to show me JUST the Release and then the add/remove and net #'s without the details of what was added or removed. I am not a developer so I'm wondering if someone has already modified this and could share with me
Release Scope Change App
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <!-- Copyright (c) 2011 Rally Software Development Corp. All rights reserved --> <html> <head> <title>Release Scope Change</title> <meta name="Name" content="App: Release Scope Change"/> <meta name="Version" content="2012.01.14"/> <meta name="Vendor" content="Rally Software"/> <script type="text/javascript" src="/apps/1.33/sdk.js?apiVersion=1.29"></script> <script type="text/javascript"> var APP_TYPE = 'Release'; var START_DATE_NAME = "ReleaseStartDate"; var END_DATE_NAME = "ReleaseDate"; var ESTIMATE_UNIT_NAME = 'ReleaseEstimateUnitName'; function ReleaseScopeChange() { var dropdown; var wait; var prefixes = { 'storyPrefix':null, 'defectPrefix':null, 'defectSuitePrefix':null, 'testSetPrefix':null }; var planEstimateLabel; var timeboxDays; var dataAddedOrRemoved; var rallyDataSource; function dateDiff(date1, date2) { return Math.abs(Math.floor(dojo.date.difference(date1, date2))); } function fromISOString(date, ignoreTime) { var newDate = dojo.date.stamp.fromISOString(date.replace(/Z/, "")); if (ignoreTime) { newDate.setHours(0, 0, 0, 0); } return newDate; } function getFormattedId(description) { var artifactName = description.split("["); if (typeof artifactName[1] === 'undefined') { artifactName = description.split(":"); } if (typeof artifactName[1] === 'undefined') { return null; } var formattedID = artifactName[1].split(":"); formattedID = formattedID[0].replace(/^\s*|\s*$/g, ''); return formattedID; } function byDesc(property) { return function(o, p) { var a,b; if (typeof o === 'object' && typeof p === 'object' && o && p) { a = o[property]; b = p[property]; if (a === b) { return 0; } if (typeof a === typeof b) { return a < b ? 1 : -1; } return typeof a < typeof b ? 1 : -1; } }; } function buildOrFilterArray(artifacts, fieldName, fieldValue) { var filterArray = []; dojo.forEach(artifacts, function(artifact, i) { filterArray.push("" + fieldName + " = " + artifact[fieldValue]); }); return rally.sdk.util.Query.or(filterArray); } function checkSchedule(description) { if (/Unscheduled/.test(description)) { return "Removed"; } if (/Scheduled/.test(description)) { return "Added"; } } function parseScopeRevisions(revisions, timeboxStart, timeboxEnd, prefixes) { var storyIds = []; var defectIds = []; var defectSuiteIds = []; function buildIdObject() { objId = { "FormattedID" : formattedIdOnly, "Status" : checkSchedule(splitRevision[num]), "PrefixID" : formattedIdWithPrefix, "User" : revisions[i].User, "CreationDate" : dataDate }; return objId; } for (var i = 0; i < revisions.length; i++) { var dataDate = fromISOString(revisions[i].CreationDate, false); var endDate = fromISOString(timeboxEnd, true); endDate.setHours(23, 59, 59, 0); if (/Scheduled|Unscheduled/.test(revisions[i].Description) && dataDate >= fromISOString(timeboxStart, true) && dataDate <= endDate) { var splitRevision = revisions[i].Description.split(','); for (var num = 0; num < splitRevision.length; num++) { if (/Scheduled|Unscheduled/.test(splitRevision[num])) { var formattedIdWithPrefix = getFormattedId(splitRevision[num]); if (formattedIdWithPrefix !== null) { var formattedIdOnly = formattedIdWithPrefix.replace(/[^0-9]/g, ""); if (formattedIdWithPrefix.indexOf(prefixes.testSetPrefix) >= 0) { } else if (formattedIdWithPrefix.indexOf(prefixes.defectSuitePrefix) >= 0) { defectSuiteIds.push(buildIdObject()); } else if (formattedIdWithPrefix.indexOf(prefixes.defectPrefix) >= 0) { defectIds.push(buildIdObject()); } else if (formattedIdWithPrefix.indexOf(prefixes.storyPrefix) >= 0) { storyIds.push(buildIdObject()); } } } } } } allWorkProductIds = { "storyIds" : storyIds, "defectIds" : defectIds, "defectSuiteIds" : defectSuiteIds }; return allWorkProductIds; } function calculateLastDayShown(timeboxDays) { var timeboxLength = timeboxDays.length - 1; var today = new Date(); today.setHours(0, 0, 0, 0); if (timeboxDays[timeboxLength] <= today) { return dateDiff(timeboxDays[0], timeboxDays[timeboxLength]); } else { return dateDiff(timeboxDays[0], today); } } function createObjectResult(results) { var newArr = []; for (var i = 0; i < results.length; i++) { if (results[i].PlanEstimate === null) { newArr[results[i].FormattedID.replace(/[^0-9]/g, "")] = { "ObjectID" : results[i].ObjectID, "PlanEstimate" : 0, "Project" : results[i].Project._refObjectName, "Name" : results[i].Name, "Type" : results[i]._type, "_ref" : results[i]._ref }; } else { newArr[results[i].FormattedID.replace(/[^0-9]/g, "")] = { "ObjectID" : results[i].ObjectID, "PlanEstimate" : results[i].PlanEstimate, "Project" : results[i].Project._refObjectName, "Name" : results[i].Name, "Type" : results[i]._type, "_ref" : results[i]._ref }; } } return newArr; } function buildWorkProductArr(objectType, ids, artifacts) { var workProductArr = []; for (var cnt = 0; cnt < ids.length; cnt++) { var artifactIndex = ids[cnt].FormattedID; var estimate = 0; if (typeof artifacts[artifactIndex] === 'undefined') { workProductArr[cnt] = { "FormattedID" : ids[cnt].PrefixID, "PlanEstimate" : estimate, "ObjectID" : 0, "Name" : '<i>' + objectType + ' Deleted</i>', "Project" : '', "CreationDate" : ids[cnt].CreationDate, "User" : ids[cnt].User, "Status" : ids[cnt].Status, "_ref" : ids[cnt]._ref }; } else { workProductArr[cnt] = { "FormattedID" : ids[cnt].PrefixID, "PlanEstimate" : artifacts[artifactIndex].PlanEstimate, "ObjectID" : artifacts[artifactIndex].ObjectID, "Name" : artifacts[artifactIndex].Name, "Project" : artifacts[artifactIndex].Project, "CreationDate" : ids[cnt].CreationDate, "User" : ids[cnt].User, "Status" : ids[cnt].Status, "Type" : artifacts[artifactIndex].Type, "_ref" : artifacts[artifactIndex]._ref }; } } return workProductArr; } function getTimeboxDays(timeboxStart, timeboxEnd) { var timeboxDays = []; timeboxStart = fromISOString(timeboxStart, true); timeboxEnd = fromISOString(timeboxEnd, true); var dayNumber = 0; var dayDate; var daysInTimebox = dateDiff(timeboxStart, timeboxEnd) + 1; for (var i = 0; i < daysInTimebox; i++) { dayDate = new Date(timeboxStart.getTime()); dayDate.setDate(dayDate.getDate() + i); timeboxDays[i] = dayDate; } return timeboxDays; } function buildQueryObject(objectType, filter) { queryObject = { key: objectType, type: objectType, fetch: 'formattedID,objectID,planEstimate,project,name', query: filter, order: 'FormattedID', project: null }; return queryObject; } function showAggregateData(added, removed, addedEst, removedEst) { var net = added - removed; var netEst = addedEst - removedEst; dojo.byId('aggregate_data').innerHTML = ""; dojo.byId('aggregate_data').innerHTML = "<table><tr>" + "<td width=20></td><td width=140></td><th width=50 align=left><b>Count</th>" + "<th width=100 align=left><b>" + planEstimateLabel + "</b></th>" + "<tr><td width=20 align=right><img src='/slm/mashup/1.11/images/plus.gif'></td>" + "<th width=140 align=left> Total Added </th>" + "<td width=50 align=left>" + added + "</td>" + "<td width=100 align=left>" + addedEst.toFixed(1) + "</td></tr><tr><td width=20 align=right><img src='/slm/mashup/1.11/images/minus.gif'></td>" + "<th width=140 align=left> Total Removed </th>" + "<td width=50 align=left>" + removed + "</td>" + "<td width=100 align=left>" + removedEst.toFixed(1) + "</td></tr><tr><td width=20 align=right></td>" + "<th width=140 align=left><b>Net </b></th>" + "<td width=50 align=left><b> " + net + "</b></td>" + "<td width=100 align=left><b>" + netEst.toFixed(1) + " " + "</b></td></tr></table>"; dojo.byId('aggregate_data').style.visibility = "visible"; } function buildHeader(creationDate) { return "</table><table class='data-table'>" + "<tr><th width=150 style='border-bottom: 0px;'><h4>" + dojo.date.locale.format(creationDate, {selector:"date",datePattern:"EEEE, MM/dd/yyyy"}) + "</h4></th>" + "<td width=20 style='border-bottom: 0px;'></td>" + "<th width=60><b>ID</b></th><th width=450><b>Name</b></th>" + "<th width=150><b>Project</b></th><th width=50><b>Est</b></th>" + "<th width=50><b>User</b></th></tr>"; } function buildDataTable(workProduct, image) { var link = new rally.sdk.ui.basic.Link({item: workProduct}).renderToHtml(); var link2 = new rally.sdk.ui.basic.Link({item: workProduct, text: workProduct.Name}).renderToHtml(); var imgUrl = "/slm/mashup/1.11/images/"; return "<tr><td width=60 style='border-bottom: 0px;border-top: 0px'>" + "<td width=20 style='border-bottom: 0px;border-top: 0px'>" + "<img align='left' src='" + imgUrl + image + ".gif' align='right'></img><td width=60>" + link + "</td><td width=450>" + link2 + "</td><td width=150>" + workProduct.Project + "</td><td width=50>" + workProduct.PlanEstimate + "</td><td wdith=50>" + workProduct.User._refObjectName + "</td></tr>"; } function computeTotalEstimate(totals) { var totalEst = 0; for (var ind in totals) { if (totals[ind] > 0) { totalEst += totals[ind]; } } return totalEst; } function drawTable(newScope) { dojo.byId("info_msg").innerHTML = ""; var results = ''; var image = ''; var diff = 0; var totalRemoved = 0; var totalAdded = 0; var totalRemovedEst = {}; var totalAddedEst = {}; var tmpDate = new Date(); var dateCnt = calculateLastDayShown(timeboxDays); var filter; tmpDate.setYear(2002); //set to some arbituary date tmpDate.setHours(0, 0, 0, 0); dojo.byId('table_div').innerHTML = results; // determine what filter is selected var workFilters = ["all_work", "added_work", "removed_work"]; for (var ind = 0; ind < workFilters.length; ind++) { if (dojo.byId(workFilters[ind]).checked) { filter = dojo.byId(workFilters[ind]).value; } } results = "<table id='data_table' class='data-table'>"; for (var i = 0; i < dataAddedOrRemoved.length; i++) { var data = dataAddedOrRemoved[i]; if (data.Status === 'Removed') { image = 'minus'; totalRemoved = totalRemoved + 1; totalRemovedEst[data.FormattedID] = data.PlanEstimate; } else { image = 'plus'; totalAdded = totalAdded + 1; totalAddedEst[data.FormattedID] = data.PlanEstimate; } // only show data based on filter criteria (e.g. All, Removed, Added) if (filter === 'All' || data.Status === filter) { var creationDate = data.CreationDate; creationDate.setHours(0, 0, 0, 0); // first occurrence of revision date if (Date.parse(tmpDate) !== Date.parse(creationDate)) { diff = dateDiff(timeboxDays[0], creationDate); results += buildHeader(creationDate); results += buildDataTable(data, image); tmpDate = creationDate; dateCnt = diff - 1; //date desc so need to subtract 1 } else { results += buildDataTable(data, image); tmpDate = creationDate; } } } if (typeof newScope !== 'undefined') { totalAddedEst = computeTotalEstimate(totalAddedEst); totalRemovedEst = computeTotalEstimate(totalRemovedEst); showAggregateData(totalAdded, totalRemoved, totalAddedEst, totalRemovedEst); } results += "</table>"; dojo.byId("radios").style.visibility = "visible"; dojo.byId("table_div").style.visibility = "visible"; dojo.byId('table_div').innerHTML = results; } function processError(errorNum) { var errorMsg = []; errorMsg[0] = "<br> No work added or removed for this " + APP_TYPE.toLowerCase() + "."; errorMsg[1] = "<br> " + APP_TYPE + " has not started yet."; wait.hide(); dojo.byId("aggregate_data").style.visibility = "hidden"; dojo.byId("table_div").style.visibility = "hidden"; dojo.byId('info_msg').innerHTML = errorMsg[errorNum]; return null; } function getWorkProducts(workProductIds, days) { var storyIds = workProductIds.storyIds; var defectIds = workProductIds.defectIds; var defectSuiteIds = workProductIds.defectSuiteIds; var workAddedOrRemoved = []; function findDefectSuiteCallback(results) { if (results.defectSuite.length > 0) { var defectSuitesAddedOrRemoved = buildWorkProductArr('Defect Suite', defectSuiteIds, createObjectResult(results.defectSuite)); workAddedOrRemoved = workAddedOrRemoved.concat(defectSuitesAddedOrRemoved); } workAddedOrRemoved.sort(byDesc('CreationDate')); dataAddedOrRemoved = workAddedOrRemoved; //chart data timeboxDays = days; var newScope = "true"; drawTable(newScope); wait.hide(); } function findDefectCallback(results) { if (results.defect.length > 0) { var defectsAddedOrRemoved = buildWorkProductArr('Defect', defectIds, createObjectResult(results.defect)); workAddedOrRemoved = workAddedOrRemoved.concat(defectsAddedOrRemoved); } if (defectSuiteIds.length === 0) { results = {"defectSuite" : []}; findDefectSuiteCallback(results); } else { var filter = buildOrFilterArray(defectSuiteIds, "FormattedID", "FormattedID"); rallyDataSource.findAll(buildQueryObject('defectSuite', filter), findDefectSuiteCallback); } } function findStoryCallback(results) { if (results.hierarchicalRequirement.length > 0) { var storiesAddedOrRemoved = buildWorkProductArr('Story', storyIds, createObjectResult(results.hierarchicalRequirement)); workAddedOrRemoved = workAddedOrRemoved.concat(storiesAddedOrRemoved); } if (defectIds.length === 0) { results = {"defect" : [] }; findDefectCallback(results); } else { var filter = buildOrFilterArray(defectIds, "FormattedID", "FormattedID"); rallyDataSource.findAll(buildQueryObject('defect', filter), findDefectCallback); } } if (storyIds.length === 0 && defectIds.length === 0 && defectSuiteIds.length === 0) { processError(0); return null; } if (storyIds.length === 0) { results = {"hierarchicalRequirement" : []}; findStoryCallback(results); } else { var filter = buildOrFilterArray(storyIds, "FormattedID", "FormattedID"); rallyDataSource.findAll(buildQueryObject('hierarchicalRequirement', filter), findStoryCallback); } } function displayTimeboxInfo(days) { var now = new Date(); var endDate = timeboxDays[days.length - 1]; endDate.setHours(23, 59, 59, 0); var startEndDate = dojo.date.locale.format(timeboxDays[0], {selector:"date",datePattern:"MM/dd/yyyy"}) + " - " + dojo.date.locale.format(timeboxDays[days.length - 1], {selector:"date",datePattern:"MM/dd/yyyy"}); if (now <= timeboxDays[0]) { dojo.byId('timeboxInfo').innerHTML = startEndDate + " (" + timeboxDays.length + " Days, Not Started)"; } else if (now <= endDate) { var dayTxt = "Days"; var daysLeft = dateDiff(endDate, now) + 1; if (daysLeft === 1) { dayTxt = "Day"; } dojo.byId('timeboxInfo').innerHTML = startEndDate + " (" + days.length + " Days, " + daysLeft + " " + dayTxt + " remaining)"; } else { dojo.byId('timeboxInfo').innerHTML = startEndDate + " (" + days.length + " Days, Done)"; } } function processMainQuery(results) { var now = new Date(); timeboxDays = getTimeboxDays(dropdown.getSelectedStart(), dropdown.getSelectedEnd()); displayTimeboxInfo(timeboxDays); // return if start date is in the future if (now >= timeboxDays[0]) { planEstimateLabel = results.planEstUnit[0][ESTIMATE_UNIT_NAME]; var workProductIds = parseScopeRevisions(results.timeboxRevisions, dropdown.getSelectedStart(), dropdown.getSelectedEnd(), prefixes); getWorkProducts(workProductIds, timeboxDays); } else { processError(1); } } function runMainQuery() { var filter = "((( " + START_DATE_NAME + " = " + dropdown.getSelectedStart() + ") AND (" + END_DATE_NAME + " = " + dropdown.getSelectedEnd() + ")) AND (Name = " + '\"' + dropdown.getSelectedName() + '\"))'; var queryObjectArr = []; queryObjectArr[0] = { key: 'planEstUnit', type: 'WorkspaceConfiguration', fetch: ESTIMATE_UNIT_NAME }; queryObjectArr[1] = { key: '#timeboxOids', type: APP_TYPE, fetch: 'ObjectID,Name,project,' + START_DATE_NAME + ',' + END_DATE_NAME, query: filter, order: END_DATE_NAME + ' desc' }; queryObjectArr[2] = { key: 'timeboxRevisions', placeholder: '${#timeboxOids/revisionhistory/revisions?fetch=creationDate,description,user&order=CreationDate}' }; rallyDataSource.findAll(queryObjectArr, processMainQuery); } function getTableData() { dojo.byId("info_msg").innerHTML = ""; dojo.byId("aggregate_data").style.visibility = "hidden"; dojo.byId("table_div").style.visibility = "hidden"; dojo.byId("radios").style.visibility = "hidden"; wait.display("wait"); runMainQuery(); } function processWorkProductPrefixes(results) { var workProducts = ['storyPrefix', 'defectPrefix', 'defectSuitePrefix', 'testSetPrefix']; // set default for prefixes prefixes.storyPrefix = "US"; prefixes.defectPrefix = "DE"; prefixes.defectSuitePrefix = "DS"; prefixes.testSetPrefix = "TS"; for (var i = 0; i < workProducts.length; i++) { if (results[workProducts[i]].length > 0) { prefixes[workProducts[i]] = results[workProducts[i]][0].FormattedID.replace(/[0-9]/g, ""); } } getTableData(); } function buildPrefixQuery(keyName, objectType) { objArr = { key: keyName, type: objectType, fetch: 'formattedID', order: 'CreationDate desc', pagesize: 1 }; return objArr; } function getWorkProductPrefixes() { var queryObjectArr = []; queryObjectArr[0] = buildPrefixQuery('storyPrefix', 'hierarchicalrequirement'); queryObjectArr[1] = buildPrefixQuery('defectPrefix', 'defect'); queryObjectArr[2] = buildPrefixQuery('defectSuitePrefix', 'defectSuite'); queryObjectArr[3] = buildPrefixQuery('testSetPrefix', 'testSet'); rallyDataSource.find(queryObjectArr, processWorkProductPrefixes); } this.display = function() { rally.sdk.ui.AppHeader.showPageTools(true); rally.sdk.ui.AppHeader.setHelpTopic("248"); wait = new rally.sdk.ui.basic.Wait({hideTarget:false}); rallyDataSource = new rally.sdk.data.RallyDataSource('__WORKSPACE_OID__', '__PROJECT_OID__', '__PROJECT_SCOPING_UP__', '__PROJECT_SCOPING_DOWN__'); var config = {showLabel: true, label: APP_TYPE}; dropdown = new rally.sdk.ui.ReleaseDropdown(config, rallyDataSource); dropdown.display("dropdown", getWorkProductPrefixes); dojo.connect(dojo.byId("all_work"), "onclick", drawTable); dojo.connect(dojo.byId("added_work"), "onclick", drawTable); dojo.connect(dojo.byId("removed_work"), "onclick", drawTable); }; } </script> <style type="text/css"> body { background: #FFF; } .lbl, .radio-lbl { font-size: 13px; text-align: left; vertical-align: bottom; } .data-table th, .data-table td { border-bottom: 2px solid #DDD; border-top: 0px solid #DDD; padding-top: 2px; padding-bottom: 2px; text-align: left; } .agg-table { border: 2px solid #DDD; text-align: center; } #wait { margin-top: 5px; width: 20px; } #radios, #aggregate-data { visibility: hidden; } </style> <script type="text/javascript"> function onLoad() { var releaseScopeChange = new ReleaseScopeChange(); releaseScopeChange.display(dojo.body()); } rally.addOnLoad(onLoad); </script> </head> <body> <table> <tr> <td class="lbl"> <div id="dropdown"></div> </td> <td id="timeboxInfo" class="lbl"></td> </tr> <tr> <td colspan="2"> <div id="wait"></div> <div id="info_msg"></div> </td> </tr> </table> <div id="radios" class="lbl"> Show Work: <label class="lbl"> <input class="radio-lbl" type="radio" name="filterRadioButton" id="all_work" value="All" checked="checked"/> All </label> <label class="lbl"> <input class="radio-lbl" type="radio" name="filterRadioButton" id="added_work" value="Added"/> Added </label> <label class="lbl"> <input class="radio-lbl" type="radio" name="filterRadioButton" id="removed_work" value="Removed"/> Removed </label> <hr width=1050 align="left" size=1 color="#dddddd"> </div> <table width=1050> <tr> <td style='width:37%'></td> <td> <div id="aggregate_data" class="agg-table"></div> </td> <td style='width:37%'></td> </tr> </table> <div id="table_div"></div> </body> </html>