Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
310 lines (276 sloc) 10.3 KB
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">
<meta name="Name" content="App: Open Defect Age"/>
<meta name="Version" content="1.0"/>
<meta name="Vendor" content="Partner: Programeter"/>
<script type="text/javascript" src="/apps/1.33/sdk.js?apiVersion=1.22"></script>
<script type="text/javascript" description="MeanAgeOfOpenDefects.js">
<!--Use only for external deployment, on internal use blank value-->
// var HOST = "https://trial.rallydev.com";
var HOST = "";
var WORKSPACE_OID = "__WORKSPACE_OID__";
var PROJECT_OID = "__PROJECT_OID__";
var PROJECT_SCOPING_UP = "__PROJECT_SCOPING_UP__";
var PROJECT_SCOPING_DOWN = "__PROJECT_SCOPING_DOWN__";
var MILS_IN_DAY = 86400000;
var DAYS_BACK = 30;
var chart;
var currentProjectDataSource;
var byPriorityTable;
var lastDefectsTable;
var fromDate = new Date(new Date().getTime() - (MILS_IN_DAY * DAYS_BACK));
var wait;
var createDate = function(dateStr) {
var date = new Date(dateStr);
if (isNaN(date.getTime())) {
date = new Date(Date.UTC(dateStr.substr(0, 4), dateStr.substr(5, 2) - 1, dateStr.substr(8, 2), dateStr.substr(11, 2), dateStr.substr(14, 2), dateStr.substr(17, 2)));
}
return date;
};
var onLoadByPiority = function() {
createByPriorityTable();
var defects = findActiveDefects(new Date(), 'Open', null);
var currentDate = new Date().getTime();
var defectsByPriorities = [];
var priorities = [];
for (var count = 0; count < defects.length; count++) {
var defect = defects[count];
var defectDate = createDate(defect.CreationDate).getTime();
var age = currentDate - defectDate;
if (!defectsByPriorities[defect.Priority]) {
defectsByPriorities[defect.Priority] = {key: defect.Priority, totalAge:0, count:0};
priorities[priorities.length] = defect.Priority;
}
var info = defectsByPriorities[defect.Priority];
info.count = info.count + 1;
info.totalAge = info.totalAge + age;
}
for (var count = 0; count < priorities.length; count ++) {
var priority = priorities[count];
var info = defectsByPriorities[priority];
var meanAge = info.totalAge / info.count;
meanAge = meanAge / MILS_IN_DAY;
meanAge = Math.round(meanAge * 10) / 10;
byPriorityTable.addRow({name:priority, age: "<div style='text-align:right'>" + meanAge + "</div>"});
}
byPriorityTable.display('byPriority');
};
var createByPriorityTable = function() {
var byPriorityTableConfig = {'columnKeys' : ['name', 'age'], columnHeaders:["<div style='text-align:center'>Priority</div>", "<div style='text-align:center'>Mean age (days)</div>"], columnWidths: ['270px', '110px']};
byPriorityTable = new rally.sdk.ui.Table(byPriorityTableConfig);
};
var allDefects = [];
var onLoadAllIssues = function(result) {
var defects = result.defects;
for (var count = 0; count < defects.length; count++) {
allDefects[allDefects.length] = defects[count];
}
allDefects.sort(function(d1, d2) {
var dateOne = createDate(d1.CreationDate).getTime();
var dateTwo = createDate(d2.CreationDate).getTime();
return dateOne - dateTwo;
});
createMeanAgeSeries();
createOldestDefectsTable();
onLoadByPiority();
wait.hide();
};
var createOldestDefectsTable = function() {
var defects = findActiveDefects(dateTimeToDate(new Date()), null, 5);
defects.sort(function(d1, d2) {
var dateOne = createDate(d1.CreationDate).getTime();
var dateTwo = createDate(d2.CreationDate).getTime();
return dateTwo - dateOne;
});
var lastDefects;
lastDefects = defects.reverse();
var lastDefectsConfig = {
columnKeys : ['name', 'age'],
columnHeaders:["<div style='text-align:center'>Summary</div>", "<div style='text-align:center'>Age (days)</div>"],
columnWidths: ['270px', '110px']};
var currentDate = new Date().getTime();
lastDefectsTable = new rally.sdk.ui.Table(lastDefectsConfig);
for (var count = 0; count < lastDefects.length; count++) {
var defect = lastDefects[count];
var defectDate = createDate(defect.CreationDate).getTime();
var age = currentDate - defectDate;
age = age / MILS_IN_DAY;
age = Math.round(age * 10) / 10;
var href = HOST + "/slm/detail/df/" + defect.ObjectID;
var html = "<div style='width:100%;overflow:hidden'><div style='width:1000px'><a target='_blank' href='" + href + "'>" + defect.FormattedID + ' - ' + defect.Name + "</a></div></div>"
lastDefectsTable.addRow({name:html, age: "<div style='text-align:right'>" + age + "</div>"});
}
lastDefectsTable.display('lastDefects');
};
var createMeanAgeSeries = function() {
if (allDefects.length > 0) {
var seriesData = [];
var startDate = dateTimeToDate(fromDate);
var endDate = dateTimeToDate(new Date());
while (startDate.getTime() <= endDate.getTime()) {
var activeDefs = findActiveDefects(startDate, 'Open', null);
var meanAge = 0;
var totalAge = 0;
for (var i = 0; i < activeDefs.length; i++) {
totalAge += startDate.getTime() - dateTimeToDate(activeDefs[i].CreationDate);
}
if (activeDefs.length > 0) {
meanAge = totalAge / activeDefs.length;
meanAge = meanAge / MILS_IN_DAY;
meanAge = Math.round(meanAge * 10) / 10;
}
seriesData[seriesData.length] = [startDate.getTime(), meanAge];
startDate.setTime(startDate.getTime() + MILS_IN_DAY);
}
chart = new EJSC.Chart("chart", {
allow_zoom: false,
allow_move: false,
show_legend: false,
legend_state: 'minimized',
show_titlebar: false,
auto_resize: true,
axis_left: {caption: "", size:0},
axis_bottom: {
caption: "Date",
formatter: new EJSC.DateFormatter({
format_string: 'DD MMM'
})
}
});
chart.addSeries(new EJSC.LineSeries(
new EJSC.ArrayDataHandler(seriesData),
{ title: "Mean Age (days)", lineWidth:3, color: 'a6b8bd'}));
}
};
var findActiveDefects = function(date, status, limit) {
var result = [];
for (var c = 0; c < allDefects.length; c++) {
var def = allDefects[c];
var isActive = false;
if (status && def.State != status) {
continue;
}
if (dateTimeToDate(def.CreationDate).getTime() <= date.getTime()) {
if (def.ClosedDate) {
if (dateTimeToDate(def.ClosedDate).getTime() >= date.getTime()) {
isActive = true;
}
} else {
isActive = true;
}
}
if (isActive) {
result[result.length] = def;
}
if (limit) {
if (result.length == limit) {
break;
}
}
}
return result;
};
var createCharts = function() {
var loadAllDefectsQuery = {
type: 'defect',
key: 'defects',
fetch:'CreationDate,ClosedDate,ObjectID,FormattedID,Name,State,Priority',
order: 'CreationDate',
query: '((ClosedDate = "null") OR (ClosedDate > "' + dojo.date.stamp.toISOString(fromDate, {zulu:true}) + '"))'};
currentProjectDataSource.findAll(loadAllDefectsQuery, onLoadAllIssues);
};
var dateTimeToDate = function(dateTime) {
dateTime = createDate(dateTime);
var date = new Date(dateTime);
date.setHours(new Date().getHours() - new Date().getUTCHours());
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
return date;
};
<!--Main function-->
var initPage = function() {
wait = new rally.sdk.ui.basic.Wait({hideTarget:true, text:'Loading...'});
currentProjectDataSource = new rally.sdk.data.RallyDataSource(WORKSPACE_OID, PROJECT_OID, PROJECT_SCOPING_UP, PROJECT_SCOPING_DOWN);
wait.display('pageContent');
createCharts();
};
rally.addOnLoad(initPage);
</script>
<style type="text/css">
.content {
float: left;
width: 820px;
}
.column {
float: left;
margin-left: 40px;
}
.first {
margin-left: 20px;
}
.row {
clear: left;
}
.small-column {
width: 380px;
}
.long-column {
width: 800px;
}
.footer {
margin-top: 80px;
}
.row H2 {
font-size: 16px;
}
</style>
</head>
<body>
<div class="content" id="pageContent">
<div class="row">
<div class="column first long-column">
<small>The Mean Age of Open Defects is a measure of how much time currently open defects stay unresolved. An
open defect is a defect that wasn't marked as closed.
</small>
<div>
<div style="float:right">
<table>
<tr>
<td>
<div style="width:20px;height:12px;background:#a6b8bd;"></div>
</td>
<td> mean age (days)</td>
</tr>
</table>
</div>
<div style="clear:both"></div>
<div id="chart" style="height:200px"></div>
</div>
</div>
</div>
<div class="row">
<div class="column first small-column">
<h2>Oldest open defects</h2>
<div id="lastDefects"></div>
</div>
<div class="column small-column">
<h2>Do we solve high priority defects first?</h2>
<div id="byPriority"></div>
</div>
</div>
<div class="row">
<div class="column first long-column footer">
<hr/>
<p>This app is powered by <a href="http://www.programeter.com" target="_blank"><img
src="https://programeter.com/logo/medium.png" alt="logo" height="10" border=0/> Programeter</a>,
metrics tracking kit for software development. Please <a
href="http://www.programeter.com" target="_blank">sign-up</a> for more software development
life-cycle metrics.</p>
</div>
</div>
</div>
</body>
</html>
You can’t perform that action at this time.