1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-22 14:52: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) ->setLimit($graph_limit)
->loadGraph(); ->loadGraph();
if (!$task_graph->isEmpty()) { 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( $message = pht(
'Task graph too large to display (this task is connected to '. 'Task graph too large to display (this task is directly connected '.
'more than %s other tasks).', 'to more than %s other tasks). Use %s to explore connected tasks.',
$graph_limit); $graph_limit,
phutil_tag('strong', array(), $search_text));
$message = phutil_tag('em', array(), $message); $message = phutil_tag('em', array(), $message);
$graph_table = id(new PHUIPropertyListView()) $graph_table = id(new PHUIPropertyListView())
->addTextContent($message); ->addTextContent($message);
} else { } 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(); $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( $parents_uri = urisprintf(
'/?subtaskIDs=%d#R', '/?subtaskIDs=%d#R',
$task->getID()); $task->getID());
@ -143,7 +156,7 @@ final class ManiphestTaskDetailController extends ManiphestController {
$graph_menu = id(new PHUIButtonView()) $graph_menu = id(new PHUIButtonView())
->setTag('a') ->setTag('a')
->setIcon('fa-search') ->setIcon('fa-search')
->setText(pht('Search...')) ->setText($search_text)
->setDropdownMenu($dropdown_menu); ->setDropdownMenu($dropdown_menu);
$graph_header = id(new PHUIHeaderView()) $graph_header = id(new PHUIHeaderView())

View file

@ -148,4 +148,16 @@ final class ManiphestTaskGraph
return $this->seedMaps[$type]; 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 $objects;
private $loadEntireGraph = false; private $loadEntireGraph = false;
private $limit; private $limit;
private $adjacent;
public function setViewer(PhabricatorUser $viewer) { public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer; $this->viewer = $viewer;
@ -33,6 +34,15 @@ abstract class PhabricatorObjectGraph
return $this->limit; 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 getEdgeTypes();
abstract protected function getParentEdgeType(); abstract protected function getParentEdgeType();
abstract protected function newQuery(); abstract protected function newQuery();
@ -40,6 +50,12 @@ abstract class PhabricatorObjectGraph
abstract protected function newTable(AphrontTableView $table); abstract protected function newTable(AphrontTableView $table);
abstract protected function isClosed($object); abstract protected function isClosed($object);
protected function newEllipsisRow() {
return array(
'...',
);
}
final public function setSeedPHID($phid) { final public function setSeedPHID($phid) {
$this->seedPHID = $phid; $this->seedPHID = $phid;
$this->edgeReach[$phid] = array_fill_keys($this->getEdgeTypes(), true); $this->edgeReach[$phid] = array_fill_keys($this->getEdgeTypes(), true);
@ -139,6 +155,32 @@ abstract class PhabricatorObjectGraph
$ancestry = $this->getEdges($this->getParentEdgeType()); $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() $objects = $this->newQuery()
->setViewer($viewer) ->setViewer($viewer)
->withPHIDs(array_keys($ancestry)) ->withPHIDs(array_keys($ancestry))
@ -157,6 +199,12 @@ abstract class PhabricatorObjectGraph
$ii = 0; $ii = 0;
$rows = array(); $rows = array();
$rowc = array(); $rowc = array();
if ($only_adjacent) {
$rows[] = $this->newEllipsisRow();
$rowc[] = 'more';
}
foreach ($ancestry as $phid => $ignored) { foreach ($ancestry as $phid => $ignored) {
$object = idx($objects, $phid); $object = idx($objects, $phid);
$rows[] = $this->newTableRow($phid, $object, $traces[$ii++]); $rows[] = $this->newTableRow($phid, $object, $traces[$ii++]);
@ -181,6 +229,11 @@ abstract class PhabricatorObjectGraph
$rowc[] = $classes; $rowc[] = $classes;
} }
if ($only_adjacent) {
$rows[] = $this->newEllipsisRow();
$rowc[] = 'more';
}
$table = id(new AphrontTableView($rows)) $table = id(new AphrontTableView($rows))
->setClassName('object-graph-table') ->setClassName('object-graph-table')
->setRowClasses($rowc); ->setRowClasses($rowc);