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:
parent
ff6b13872c
commit
f8ebc71b8f
5 changed files with 130 additions and 31 deletions
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue