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

When a task graph has too much stuff, only show adjacent nodes (direct parents/children)

Summary:
Ref T4788. This gives us a new level of graceful degradation, so now we show:

  - Zero through 100 connected tasks: whole graph.
  - More than 100 connnected tasks, but fewer than 100 direct parents/subtasks: just parents and subtasks, with "..." to hint that the graph is cut off.
  - More than 100 parents and children: just the "sorry, too much stuff" error message.

Test Plan: {F1740882}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T4788

Differential Revision: https://secure.phabricator.com/D16344
This commit is contained in:
epriestley 2016-07-28 13:54:10 -07:00
parent ef5cb0630f
commit 15c7eb1425
3 changed files with 92 additions and 14 deletions

View file

@ -94,27 +94,40 @@ final class ManiphestTaskDetailController extends ManiphestController {
->setLimit($graph_limit)
->loadGraph();
if (!$task_graph->isEmpty()) {
if ($task_graph->isOverLimit()) {
$parent_type = ManiphestTaskDependedOnByTaskEdgeType::EDGECONST;
$subtask_type = ManiphestTaskDependsOnTaskEdgeType::EDGECONST;
$parent_map = $task_graph->getEdges($parent_type);
$subtask_map = $task_graph->getEdges($subtask_type);
$parent_list = idx($parent_map, $task->getPHID(), array());
$subtask_list = idx($subtask_map, $task->getPHID(), array());
$has_parents = (bool)$parent_list;
$has_subtasks = (bool)$subtask_list;
$search_text = pht('Search...');
// First, get a count of direct parent tasks and subtasks. If there
// are too many of these, we just don't draw anything. You can use
// the search button to browse tasks with the search UI instead.
$direct_count = count($parent_list) + count($subtask_list);
if ($direct_count > $graph_limit) {
$message = pht(
'Task graph too large to display (this task is connected to '.
'more than %s other tasks).',
$graph_limit);
'Task graph too large to display (this task is directly connected '.
'to more than %s other tasks). Use %s to explore connected tasks.',
$graph_limit,
phutil_tag('strong', array(), $search_text));
$message = phutil_tag('em', array(), $message);
$graph_table = id(new PHUIPropertyListView())
->addTextContent($message);
} else {
// If there aren't too many direct tasks, but there are too many total
// tasks, we'll only render directly connected tasks.
if ($task_graph->isOverLimit()) {
$task_graph->setRenderOnlyAdjacentNodes(true);
}
$graph_table = $task_graph->newGraphTable();
}
$parent_type = ManiphestTaskDependedOnByTaskEdgeType::EDGECONST;
$subtask_type = ManiphestTaskDependsOnTaskEdgeType::EDGECONST;
$parent_map = $task_graph->getEdges($parent_type);
$subtask_map = $task_graph->getEdges($subtask_type);
$has_parents = (bool)idx($parent_map, $task->getPHID());
$has_subtasks = (bool)idx($subtask_map, $task->getPHID());
$parents_uri = urisprintf(
'/?subtaskIDs=%d#R',
$task->getID());
@ -143,7 +156,7 @@ final class ManiphestTaskDetailController extends ManiphestController {
$graph_menu = id(new PHUIButtonView())
->setTag('a')
->setIcon('fa-search')
->setText(pht('Search...'))
->setText($search_text)
->setDropdownMenu($dropdown_menu);
$graph_header = id(new PHUIHeaderView())

View file

@ -148,4 +148,16 @@ final class ManiphestTaskGraph
return $this->seedMaps[$type];
}
protected function newEllipsisRow() {
return array(
null,
null,
null,
null,
pht("\xC2\xB7 \xC2\xB7 \xC2\xB7"),
);
}
}

View file

@ -10,6 +10,7 @@ abstract class PhabricatorObjectGraph
private $objects;
private $loadEntireGraph = false;
private $limit;
private $adjacent;
public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
@ -33,6 +34,15 @@ abstract class PhabricatorObjectGraph
return $this->limit;
}
final public function setRenderOnlyAdjacentNodes($adjacent) {
$this->adjacent = $adjacent;
return $this;
}
final public function getRenderOnlyAdjacentNodes() {
return $this->adjacent;
}
abstract protected function getEdgeTypes();
abstract protected function getParentEdgeType();
abstract protected function newQuery();
@ -40,6 +50,12 @@ abstract class PhabricatorObjectGraph
abstract protected function newTable(AphrontTableView $table);
abstract protected function isClosed($object);
protected function newEllipsisRow() {
return array(
'...',
);
}
final public function setSeedPHID($phid) {
$this->seedPHID = $phid;
$this->edgeReach[$phid] = array_fill_keys($this->getEdgeTypes(), true);
@ -139,6 +155,32 @@ abstract class PhabricatorObjectGraph
$ancestry = $this->getEdges($this->getParentEdgeType());
$only_adjacent = $this->getRenderOnlyAdjacentNodes();
if ($only_adjacent) {
$adjacent = array(
$this->getSeedPHID() => $this->getSeedPHID(),
);
foreach ($this->getEdgeTypes() as $edge_type) {
$map = $this->getEdges($edge_type);
$direct = idx($map, $this->getSeedPHID(), array());
$adjacent += array_fuse($direct);
}
foreach ($ancestry as $key => $list) {
if (!isset($adjacent[$key])) {
unset($ancestry[$key]);
continue;
}
foreach ($list as $list_key => $item) {
if (!isset($adjacent[$item])) {
unset($ancestry[$key][$list_key]);
}
}
}
}
$objects = $this->newQuery()
->setViewer($viewer)
->withPHIDs(array_keys($ancestry))
@ -157,6 +199,12 @@ abstract class PhabricatorObjectGraph
$ii = 0;
$rows = array();
$rowc = array();
if ($only_adjacent) {
$rows[] = $this->newEllipsisRow();
$rowc[] = 'more';
}
foreach ($ancestry as $phid => $ignored) {
$object = idx($objects, $phid);
$rows[] = $this->newTableRow($phid, $object, $traces[$ii++]);
@ -181,6 +229,11 @@ abstract class PhabricatorObjectGraph
$rowc[] = $classes;
}
if ($only_adjacent) {
$rows[] = $this->newEllipsisRow();
$rowc[] = 'more';
}
$table = id(new AphrontTableView($rows))
->setClassName('object-graph-table')
->setRowClasses($rowc);