1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-26 00:32:42 +01:00

Replace the chart in Maniphest Reports with a chart driven by Facts

Summary:
Depends on D20485. Ref T13279. This removes the ad-hoc charting in Maniphest and replaces it with a Facts-based chart.

(To do this, we build a dashboard panel inline and render it.)

Test Plan: {F6412720}

Reviewers: amckinley

Reviewed By: amckinley

Subscribers: yelirekim

Maniphest Tasks: T13279

Differential Revision: https://secure.phabricator.com/D20486
This commit is contained in:
epriestley 2019-04-29 11:55:22 -07:00
parent ff6b13872c
commit f8ebc71b8f
5 changed files with 130 additions and 31 deletions

View file

@ -9,6 +9,11 @@ final class PhabricatorChartDataset
return $this->function;
}
public function setFunction(PhabricatorComposeChartFunction $function) {
$this->function = $function;
return $this;
}
public static function newFromDictionary(array $map) {
PhutilTypeSpec::checkMap(
$map,

View file

@ -30,6 +30,7 @@ final class PhabricatorChartFunctionArgument
'fact-key' => true,
'function' => true,
'number' => true,
'phid' => true,
);
if (!isset($types[$type])) {
@ -51,6 +52,10 @@ final class PhabricatorChartFunctionArgument
public function newValue($value) {
switch ($this->getType()) {
case 'phid':
// TODO: This could be validated better, but probably should not be
// a primitive type.
return $value;
case 'fact-key':
if (!is_string($value)) {
throw new Exception(

View file

@ -35,25 +35,38 @@ final class PhabricatorFactChartFunction
$conn = $table->establishConnection('r');
$table_name = $table->getTableName();
$data = queryfx_all(
$where = array();
$where[] = qsprintf(
$conn,
'SELECT value, epoch FROM %T WHERE keyID = %d ORDER BY epoch ASC',
$table_name,
'keyID = %d',
$key_id);
if (!$data) {
return;
$parser = $this->getArgumentParser();
$parts = $fact->buildWhereClauseParts($conn, $parser);
foreach ($parts as $part) {
$where[] = $part;
}
$data = queryfx_all(
$conn,
'SELECT value, epoch FROM %T WHERE %LA ORDER BY epoch ASC',
$table_name,
$where);
$map = array();
foreach ($data as $row) {
$value = (int)$row['value'];
$epoch = (int)$row['epoch'];
if ($data) {
foreach ($data as $row) {
$value = (int)$row['value'];
$epoch = (int)$row['epoch'];
if (!isset($map[$epoch])) {
$map[$epoch] = 0;
if (!isset($map[$epoch])) {
$map[$epoch] = 0;
}
$map[$epoch] += $value;
}
$map[$epoch] += $value;
}
$this->map = $map;

View file

@ -38,7 +38,46 @@ abstract class PhabricatorFact extends Phobject {
abstract protected function newTemplateDatapoint();
final public function getFunctionArguments() {
return array();
$key = $this->getKey();
$argv = array();
if (preg_match('/\.project\z/', $key)) {
$argv[] = id(new PhabricatorChartFunctionArgument())
->setName('phid')
->setType('phid');
}
if (preg_match('/\.owner\z/', $key)) {
$argv[] = id(new PhabricatorChartFunctionArgument())
->setName('phid')
->setType('phid');
}
return $argv;
}
final public function buildWhereClauseParts(
AphrontDatabaseConnection $conn,
PhabricatorChartFunctionArgumentParser $arguments) {
$where = array();
$has_phid = $this->getFunctionArguments();
if ($has_phid) {
$phid = $arguments->getArgumentValue('phid');
$dimension_id = id(new PhabricatorFactObjectDimension())
->newDimensionID($phid);
$where[] = qsprintf(
$conn,
'dimensionID = %d',
$dimension_id);
}
return $where;
}
}

View file

@ -337,7 +337,8 @@ final class ManiphestReportController extends ManiphestController {
'the project recently, it is counted on the day it was '.
'opened, not the day it was categorized. If a task was part '.
'of this project in the past but no longer is, it is not '.
'counted at all.');
'counted at all. This table may not agree exactly with the chart '.
'above.');
$header = pht('Task Burn Rate for Project %s', $handle->renderLink());
$caption = phutil_tag('p', array(), $inst);
} else {
@ -379,26 +380,62 @@ final class ManiphestReportController extends ManiphestController {
list($burn_x, $burn_y) = $this->buildSeries($data);
require_celerity_resource('d3');
require_celerity_resource('phui-chart-css');
if ($project_phid) {
$argv = array(
'sum',
array(
'accumulate',
array('fact', 'tasks.open-count.create.project', $project_phid),
),
array(
'accumulate',
array('fact', 'tasks.open-count.status.project', $project_phid),
),
array(
'accumulate',
array('fact', 'tasks.open-count.assign.project', $project_phid),
),
);
} else {
$argv = array(
'sum',
array('accumulate', array('fact', 'tasks.open-count.create')),
array('accumulate', array('fact', 'tasks.open-count.status')),
);
}
Javelin::initBehavior('line-chart-legacy', array(
'hardpoint' => $id,
'x' => array(
$burn_x,
),
'y' => array(
$burn_y,
),
'xformat' => 'epoch',
'yformat' => 'int',
));
$function = id(new PhabricatorComposeChartFunction())
->setArguments(array($argv));
$box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Burnup Rate'))
->appendChild($chart);
$datasets = array(
id(new PhabricatorChartDataset())
->setFunction($function),
);
return array($filter, $box, $panel);
$chart = id(new PhabricatorFactChart())
->setDatasets($datasets);
$engine = id(new PhabricatorChartEngine())
->setViewer($viewer)
->setChart($chart);
$chart = $engine->getStoredChart();
$panel_type = id(new PhabricatorDashboardChartPanelType())
->getPanelTypeKey();
$chart_panel = id(new PhabricatorDashboardPanel())
->setPanelType($panel_type)
->setName(pht('Burnup Rate'))
->setProperty('chartKey', $chart->getChartKey());
$chart_view = id(new PhabricatorDashboardPanelRenderingEngine())
->setViewer($viewer)
->setPanel($chart_panel)
->setParentPanelPHIDs(array())
->renderPanel();
return array($filter, $chart_view, $panel);
}
private function renderReportFilters(array $tokens, $has_window) {