Add "Oldest" and "Fixed Last 7d" columns to Maniphest reports
Summary: Part of a user feature request, see T994. Test Plan: Looked at data in columns, seemed to line up with reality. Reviewers: btrahan Reviewed By: btrahan CC: aran, epriestley, sandra Maniphest Tasks: T994 Differential Revision: https://secure.phabricator.com/D1944
This commit is contained in:
parent
6a13b3ea7e
commit
7cfe006c7f
|
@ -39,6 +39,18 @@ final class ManiphestTaskPriority extends ManiphestConstants {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getTaskBriefPriorityMap() {
|
||||||
|
return array(
|
||||||
|
self::PRIORITY_UNBREAK_NOW => 'Unbreak!',
|
||||||
|
self::PRIORITY_TRIAGE => 'Triage',
|
||||||
|
self::PRIORITY_HIGH => 'High',
|
||||||
|
self::PRIORITY_NORMAL => 'Normal',
|
||||||
|
self::PRIORITY_LOW => 'Low',
|
||||||
|
self::PRIORITY_WISH => 'Wish',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function getLoadMap() {
|
public static function getLoadMap() {
|
||||||
return array(
|
return array(
|
||||||
self::PRIORITY_UNBREAK_NOW => 16,
|
self::PRIORITY_UNBREAK_NOW => 16,
|
||||||
|
|
|
@ -371,6 +371,8 @@ final class ManiphestReportController extends ManiphestController {
|
||||||
|
|
||||||
$tasks = $query->execute();
|
$tasks = $query->execute();
|
||||||
|
|
||||||
|
$recently_closed = $this->loadRecentlyClosedTasks();
|
||||||
|
|
||||||
$date = phabricator_date(time(), $user);
|
$date = phabricator_date(time(), $user);
|
||||||
|
|
||||||
switch ($this->view) {
|
switch ($this->view) {
|
||||||
|
@ -378,6 +380,11 @@ final class ManiphestReportController extends ManiphestController {
|
||||||
$result = mgroup($tasks, 'getOwnerPHID');
|
$result = mgroup($tasks, 'getOwnerPHID');
|
||||||
$leftover = idx($result, '', array());
|
$leftover = idx($result, '', array());
|
||||||
unset($result['']);
|
unset($result['']);
|
||||||
|
|
||||||
|
$result_closed = mgroup($recently_closed, 'getOwnerPHID');
|
||||||
|
$leftover_closed = idx($result_closed, '', array());
|
||||||
|
unset($result_closed['']);
|
||||||
|
|
||||||
$leftover_name = phutil_render_tag(
|
$leftover_name = phutil_render_tag(
|
||||||
'a',
|
'a',
|
||||||
array(
|
array(
|
||||||
|
@ -390,6 +397,7 @@ final class ManiphestReportController extends ManiphestController {
|
||||||
break;
|
break;
|
||||||
case 'project':
|
case 'project':
|
||||||
$result = array();
|
$result = array();
|
||||||
|
$leftover = array();
|
||||||
foreach ($tasks as $task) {
|
foreach ($tasks as $task) {
|
||||||
$phids = $task->getProjectPHIDs();
|
$phids = $task->getProjectPHIDs();
|
||||||
if ($phids) {
|
if ($phids) {
|
||||||
|
@ -400,6 +408,20 @@ final class ManiphestReportController extends ManiphestController {
|
||||||
$leftover[] = $task;
|
$leftover[] = $task;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$result_closed = array();
|
||||||
|
$leftover_closed = array();
|
||||||
|
foreach ($recently_closed as $task) {
|
||||||
|
$phids = $task->getProjectPHIDs();
|
||||||
|
if ($phids) {
|
||||||
|
foreach ($phids as $project_phid) {
|
||||||
|
$result_closed[$project_phid][] = $task;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$leftover_closed[] = $task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$leftover_name = phutil_render_tag(
|
$leftover_name = phutil_render_tag(
|
||||||
'a',
|
'a',
|
||||||
array(
|
array(
|
||||||
|
@ -418,6 +440,9 @@ final class ManiphestReportController extends ManiphestController {
|
||||||
|
|
||||||
$order = $request->getStr('order', 'name');
|
$order = $request->getStr('order', 'name');
|
||||||
|
|
||||||
|
require_celerity_resource('aphront-tooltip-css');
|
||||||
|
Javelin::initBehavior('phabricator-tooltips', array());
|
||||||
|
|
||||||
$rows = array();
|
$rows = array();
|
||||||
$pri_total = array();
|
$pri_total = array();
|
||||||
foreach (array_merge($handles, array(null)) as $handle) {
|
foreach (array_merge($handles, array(null)) as $handle) {
|
||||||
|
@ -429,11 +454,14 @@ final class ManiphestReportController extends ManiphestController {
|
||||||
'href' => $link.$handle->getPHID(),
|
'href' => $link.$handle->getPHID(),
|
||||||
),
|
),
|
||||||
phutil_escape_html($handle->getName()));
|
phutil_escape_html($handle->getName()));
|
||||||
|
$closed = idx($result_closed, $handle->getPHID(), array());
|
||||||
} else {
|
} else {
|
||||||
$tasks = $leftover;
|
$tasks = $leftover;
|
||||||
$name = $leftover_name;
|
$name = $leftover_name;
|
||||||
|
$closed = $leftover_closed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$taskv = $tasks;
|
||||||
$tasks = mgroup($tasks, 'getPriority');
|
$tasks = mgroup($tasks, 'getPriority');
|
||||||
|
|
||||||
$row = array();
|
$row = array();
|
||||||
|
@ -450,6 +478,31 @@ final class ManiphestReportController extends ManiphestController {
|
||||||
}
|
}
|
||||||
$row[] = number_format($total);
|
$row[] = number_format($total);
|
||||||
|
|
||||||
|
$row[] = $this->renderOldest($taskv);
|
||||||
|
|
||||||
|
$normal_or_better = array();
|
||||||
|
foreach ($taskv as $id => $task) {
|
||||||
|
if ($task->getPriority() < ManiphestTaskPriority::PRIORITY_NORMAL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$normal_or_better[$id] = $task;
|
||||||
|
}
|
||||||
|
|
||||||
|
$row[] = $this->renderOldest($normal_or_better);
|
||||||
|
|
||||||
|
if ($closed) {
|
||||||
|
$task_ids = implode(',', mpull($closed, 'getID'));
|
||||||
|
$row[] = phutil_render_tag(
|
||||||
|
'a',
|
||||||
|
array(
|
||||||
|
'href' => '/maniphest/view/custom/?s=oc&tasks='.$task_ids,
|
||||||
|
'target' => '_blank',
|
||||||
|
),
|
||||||
|
phutil_escape_html(number_format(count($closed))));
|
||||||
|
} else {
|
||||||
|
$row[] = '-';
|
||||||
|
}
|
||||||
|
|
||||||
switch ($order) {
|
switch ($order) {
|
||||||
case 'total':
|
case 'total':
|
||||||
$row['sort'] = $total;
|
$row['sort'] = $total;
|
||||||
|
@ -470,12 +523,38 @@ final class ManiphestReportController extends ManiphestController {
|
||||||
|
|
||||||
$cname = array($col_header);
|
$cname = array($col_header);
|
||||||
$cclass = array('pri right wide');
|
$cclass = array('pri right wide');
|
||||||
foreach (ManiphestTaskPriority::getTaskPriorityMap() as $pri => $label) {
|
$pri_map = ManiphestTaskPriority::getTaskBriefPriorityMap();
|
||||||
|
foreach ($pri_map as $pri => $label) {
|
||||||
$cname[] = $label;
|
$cname[] = $label;
|
||||||
$cclass[] = 'n';
|
$cclass[] = 'n';
|
||||||
}
|
}
|
||||||
$cname[] = 'Total';
|
$cname[] = 'Total';
|
||||||
$cclass[] = 'n';
|
$cclass[] = 'n';
|
||||||
|
$cname[] = javelin_render_tag(
|
||||||
|
'span',
|
||||||
|
array(
|
||||||
|
'sigil' => 'has-tooltip',
|
||||||
|
'meta' => array(
|
||||||
|
'tip' => 'Oldest open task.',
|
||||||
|
'size' => 200,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'Oldest (All)');
|
||||||
|
$cclass[] = 'n';
|
||||||
|
$cname[] = javelin_render_tag(
|
||||||
|
'span',
|
||||||
|
array(
|
||||||
|
'sigil' => 'has-tooltip',
|
||||||
|
'meta' => array(
|
||||||
|
'tip' => 'Oldest open task, excluding those with Low or Wishlist '.
|
||||||
|
'priority.',
|
||||||
|
'size' => 200,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'Oldest (Pri)');
|
||||||
|
$cclass[] = 'n';
|
||||||
|
$cname[] = 'Closed Last 7d';
|
||||||
|
$cclass[] = 'n';
|
||||||
|
|
||||||
$table = new AphrontTableView($rows);
|
$table = new AphrontTableView($rows);
|
||||||
$table->setHeaders($cname);
|
$table->setHeaders($cname);
|
||||||
|
@ -505,4 +584,71 @@ final class ManiphestReportController extends ManiphestController {
|
||||||
return array($filter, $panel);
|
return array($filter, $panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load all the tasks that have been recently closed.
|
||||||
|
*/
|
||||||
|
private function loadRecentlyClosedTasks() {
|
||||||
|
$recent_window = (60 * 60 * 24 * 7);
|
||||||
|
|
||||||
|
$table = new ManiphestTask();
|
||||||
|
$xtable = new ManiphestTransaction();
|
||||||
|
$conn_r = $table->establishConnection('r');
|
||||||
|
|
||||||
|
$tasks = queryfx_all(
|
||||||
|
$conn_r,
|
||||||
|
'SELECT t.* FROM %T t JOIN %T x ON x.taskID = t.id
|
||||||
|
WHERE t.status != 0
|
||||||
|
AND x.oldValue IN (null, %s, %s)
|
||||||
|
AND x.newValue NOT IN (%s, %s)
|
||||||
|
AND t.dateModified >= %d
|
||||||
|
AND x.dateCreated >= %d',
|
||||||
|
$table->getTableName(),
|
||||||
|
$xtable->getTableName(),
|
||||||
|
|
||||||
|
// TODO: Gross. This table is not meant to be queried like this. Build
|
||||||
|
// real stats tables.
|
||||||
|
json_encode((int)ManiphestTaskStatus::STATUS_OPEN),
|
||||||
|
json_encode((string)ManiphestTaskStatus::STATUS_OPEN),
|
||||||
|
json_encode((int)ManiphestTaskStatus::STATUS_OPEN),
|
||||||
|
json_encode((string)ManiphestTaskStatus::STATUS_OPEN),
|
||||||
|
|
||||||
|
(time() - $recent_window),
|
||||||
|
(time() - $recent_window));
|
||||||
|
|
||||||
|
return id(new ManiphestTask())->loadAllFromArray($tasks);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function renderOldest(array $tasks) {
|
||||||
|
$oldest = null;
|
||||||
|
foreach ($tasks as $id => $task) {
|
||||||
|
if (($oldest === null) ||
|
||||||
|
($task->getDateCreated() < $tasks[$oldest]->getDateCreated())) {
|
||||||
|
$oldest = $id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($oldest === null) {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
$oldest = $tasks[$oldest];
|
||||||
|
|
||||||
|
$age = (time() - $oldest->getDateCreated());
|
||||||
|
$age = number_format($age / (24 * 60 * 60)).' d';
|
||||||
|
$age = phutil_escape_html($age);
|
||||||
|
|
||||||
|
return javelin_render_tag(
|
||||||
|
'a',
|
||||||
|
array(
|
||||||
|
'href' => '/T'.$oldest->getID(),
|
||||||
|
'sigil' => 'has-tooltip',
|
||||||
|
'meta' => array(
|
||||||
|
'tip' => 'T'.$oldest->getID().': '.$oldest->getTitle(),
|
||||||
|
),
|
||||||
|
'target' => '_blank',
|
||||||
|
),
|
||||||
|
$age);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ phutil_require_module('phabricator', 'applications/maniphest/storage/transaction
|
||||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||||
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
||||||
phutil_require_module('phabricator', 'infrastructure/javelin/api');
|
phutil_require_module('phabricator', 'infrastructure/javelin/api');
|
||||||
|
phutil_require_module('phabricator', 'infrastructure/javelin/markup');
|
||||||
phutil_require_module('phabricator', 'storage/qsprintf');
|
phutil_require_module('phabricator', 'storage/qsprintf');
|
||||||
phutil_require_module('phabricator', 'storage/queryfx');
|
phutil_require_module('phabricator', 'storage/queryfx');
|
||||||
phutil_require_module('phabricator', 'view/control/table');
|
phutil_require_module('phabricator', 'view/control/table');
|
||||||
|
|
Loading…
Reference in a new issue