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:
parent
ef5cb0630f
commit
15c7eb1425
3 changed files with 92 additions and 14 deletions
|
@ -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())
|
||||||
|
|
|
@ -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"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue