1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-27 16:00:59 +01:00

Simplify and improve the "burnup" chart

Summary:
  - We incorrectly count resolution changes and other noise as opens / closes.
  - Show one graph: open bugs over time (red line minus green line). This and its derivative are the values you actually care about. It is difficult to see the derivative with both lines, but easy with one line.

Test Plan: Looked at burnup chart. Saw charty things. Verified resolution changes no longer make the line move.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran, epriestley

Maniphest Tasks: T923, T982

Differential Revision: https://secure.phabricator.com/D1945
This commit is contained in:
epriestley 2012-03-19 19:19:28 -07:00
parent 3db02a584c
commit 49cc3d9f0d
4 changed files with 43 additions and 55 deletions

View file

@ -441,7 +441,7 @@ celerity_register_resource_map(array(
), ),
'javelin-behavior-burn-chart' => 'javelin-behavior-burn-chart' =>
array( array(
'uri' => '/res/ed1bf018/rsrc/js/application/maniphest/behavior-burn-chart.js', 'uri' => '/res/053cffd4/rsrc/js/application/maniphest/behavior-burn-chart.js',
'type' => 'js', 'type' => 'js',
'requires' => 'requires' =>
array( array(

View file

@ -108,7 +108,8 @@ final class ManiphestReportController extends ManiphestController {
$data = queryfx_all( $data = queryfx_all(
$conn, $conn,
'SELECT x.newValue, x.dateCreated FROM %T x %Q WHERE transactionType = %s 'SELECT x.oldValue, x.newValue, x.dateCreated FROM %T x %Q
WHERE transactionType = %s
ORDER BY x.dateCreated ASC', ORDER BY x.dateCreated ASC',
$table->getTableName(), $table->getTableName(),
$joins, $joins,
@ -117,8 +118,29 @@ final class ManiphestReportController extends ManiphestController {
$stats = array(); $stats = array();
$day_buckets = array(); $day_buckets = array();
foreach ($data as $row) { $open_tasks = array();
$is_close = $row['newValue'];
foreach ($data as $key => $row) {
// NOTE: Hack to avoid json_decode().
$oldv = trim($row['oldValue'], '"');
$newv = trim($row['newValue'], '"');
$old_is_open = ($oldv === (string)ManiphestTaskStatus::STATUS_OPEN);
$new_is_open = ($newv === (string)ManiphestTaskStatus::STATUS_OPEN);
$is_open = ($new_is_open && !$old_is_open);
$is_close = ($old_is_open && !$new_is_open);
$data[$key]['_is_open'] = $is_open;
$data[$key]['_is_close'] = $is_close;
if (!$is_open && !$is_close) {
// This is either some kind of bogus event, or a resolution change
// (e.g., resolved -> invalid). Just skip it.
continue;
}
$day_bucket = __phabricator_format_local_time( $day_bucket = __phabricator_format_local_time(
$row['dateCreated'], $row['dateCreated'],
$user, $user,
@ -286,7 +308,7 @@ final class ManiphestReportController extends ManiphestController {
), ),
''); '');
list($open_x, $close_x, $open_y, $close_y) = $this->buildSeries($data); list($burn_x, $burn_y) = $this->buildSeries($data);
require_celerity_resource('raphael-core'); require_celerity_resource('raphael-core');
require_celerity_resource('raphael-g'); require_celerity_resource('raphael-g');
@ -295,12 +317,10 @@ final class ManiphestReportController extends ManiphestController {
Javelin::initBehavior('burn-chart', array( Javelin::initBehavior('burn-chart', array(
'hardpoint' => $id, 'hardpoint' => $id,
'x' => array( 'x' => array(
$open_x, $burn_x,
$close_x,
), ),
'y' => array( 'y' => array(
$open_y, $burn_y,
$close_y,
), ),
)); ));
@ -308,40 +328,21 @@ final class ManiphestReportController extends ManiphestController {
} }
private function buildSeries(array $data) { private function buildSeries(array $data) {
$open_count = 0; $out = array();
$close_count = 0;
$open_x = array();
$open_y = array();
$close_x = array();
$close_y = array();
$start = (int)idx(head($data), 'dateCreated', time());
$open_x[] = $start;
$open_y[] = $open_count;
$close_x[] = $start;
$close_y[] = $close_count;
$counter = 0;
foreach ($data as $row) { foreach ($data as $row) {
$t = (int)$row['dateCreated']; $t = (int)$row['dateCreated'];
if ($row['newValue']) { if ($row['_is_close']) {
++$close_count; --$counter;
$close_x[] = $t; $out[$t] = $counter;
$close_y[] = $close_count; } else if ($row['_is_open']) {
} else { ++$counter;
++$open_count; $out[$t] = $counter;
$open_x[] = $t;
$open_y[] = $open_count;
} }
} }
$close_x[] = time(); return array(array_keys($out), array_values($out));
$close_y[] = $close_count;
$open_x[] = time();
$open_y[] = $open_count;
return array($open_x, $close_x, $open_y, $close_y);
} }
private function formatBurnRow($label, $info) { private function formatBurnRow($label, $info) {

View file

@ -9,6 +9,7 @@
phutil_require_module('phabricator', 'aphront/response/404'); phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'aphront/response/redirect'); phutil_require_module('phabricator', 'aphront/response/redirect');
phutil_require_module('phabricator', 'applications/maniphest/constants/priority'); phutil_require_module('phabricator', 'applications/maniphest/constants/priority');
phutil_require_module('phabricator', 'applications/maniphest/constants/status');
phutil_require_module('phabricator', 'applications/maniphest/constants/transactiontype'); phutil_require_module('phabricator', 'applications/maniphest/constants/transactiontype');
phutil_require_module('phabricator', 'applications/maniphest/controller/base'); phutil_require_module('phabricator', 'applications/maniphest/controller/base');
phutil_require_module('phabricator', 'applications/maniphest/query'); phutil_require_module('phabricator', 'applications/maniphest/query');

View file

@ -7,6 +7,7 @@
JX.behavior('burn-chart', function(config) { JX.behavior('burn-chart', function(config) {
var h = JX.$(config.hardpoint); var h = JX.$(config.hardpoint);
var p = JX.$V(h); var p = JX.$V(h);
var d = JX.Vector.getDim(h); var d = JX.Vector.getDim(h);
@ -25,7 +26,7 @@ JX.behavior('burn-chart', function(config) {
axis: "0 0 1 1", axis: "0 0 1 1",
shade: true, shade: true,
gutter: 1, gutter: 1,
colors: ['#d00', '#090'] colors: ['#d06']
}); });
@ -45,13 +46,8 @@ JX.behavior('burn-chart', function(config) {
} }
} }
// Get rid of the green shading below closed tasks.
l.shades[1].attr({fill: '#fff', opacity: 1});
l.hoverColumn(function() { l.hoverColumn(function() {
var open = 0; var open = 0;
for (var ii = 0; ii < config.x[0].length; ii++) { for (var ii = 0; ii < config.x[0].length; ii++) {
if (config.x[0][ii] > this.axis) { if (config.x[0][ii] > this.axis) {
@ -60,23 +56,13 @@ JX.behavior('burn-chart', function(config) {
open = config.y[0][ii]; open = config.y[0][ii];
} }
var closed = 0;
for (var ii = 0; ii < config.x[1].length; ii++) {
if (config.x[1][ii] > this.axis) {
break;
}
closed = config.y[1][ii];
}
var date = new Date(parseInt(this.axis, 10) * 1000).toLocaleDateString(); var date = new Date(parseInt(this.axis, 10) * 1000).toLocaleDateString();
var total = open + " Total Tasks"; var total = open + " Open Tasks";
var pain = (open - closed) + " Open Tasks";
var tag = r.tag( var tag = r.tag(
this.x, this.x,
this.y[0], this.y[0],
[date, total, pain].join("\n"), [date, total].join("\n"),
180, 180,
24); 24);
tag tag