Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14095982
D20164.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
15 KB
Referenced Files
None
Subscribers
None
D20164.diff
View Options
diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -9,7 +9,7 @@
'names' => array(
'conpherence.pkg.css' => '3c8a0668',
'conpherence.pkg.js' => '020aebcf',
- 'core.pkg.css' => '4ed8ce1f',
+ 'core.pkg.css' => '85a1da99',
'core.pkg.js' => '5c737607',
'differential.pkg.css' => 'b8df73d4',
'differential.pkg.js' => '67c9ea4c',
@@ -30,7 +30,7 @@
'rsrc/css/aphront/notification.css' => '30240bd2',
'rsrc/css/aphront/panel-view.css' => '46923d46',
'rsrc/css/aphront/phabricator-nav-view.css' => 'f8a0c1bf',
- 'rsrc/css/aphront/table-view.css' => 'daa1f9df',
+ 'rsrc/css/aphront/table-view.css' => '205053cd',
'rsrc/css/aphront/tokenizer.css' => 'b52d0668',
'rsrc/css/aphront/tooltip.css' => 'e3f2412f',
'rsrc/css/aphront/typeahead-browse.css' => 'b7ed02d2',
@@ -520,7 +520,7 @@
'aphront-list-filter-view-css' => 'feb64255',
'aphront-multi-column-view-css' => 'fbc00ba3',
'aphront-panel-view-css' => '46923d46',
- 'aphront-table-view-css' => 'daa1f9df',
+ 'aphront-table-view-css' => '205053cd',
'aphront-tokenizer-control-css' => 'b52d0668',
'aphront-tooltip-css' => 'e3f2412f',
'aphront-typeahead-control-css' => '8779483d',
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1714,6 +1714,7 @@
'ManiphestTaskFerretEngine' => 'applications/maniphest/search/ManiphestTaskFerretEngine.php',
'ManiphestTaskFulltextEngine' => 'applications/maniphest/search/ManiphestTaskFulltextEngine.php',
'ManiphestTaskGraph' => 'infrastructure/graph/ManiphestTaskGraph.php',
+ 'ManiphestTaskGraphController' => 'applications/maniphest/controller/ManiphestTaskGraphController.php',
'ManiphestTaskHasCommitEdgeType' => 'applications/maniphest/edge/ManiphestTaskHasCommitEdgeType.php',
'ManiphestTaskHasCommitRelationship' => 'applications/maniphest/relationship/ManiphestTaskHasCommitRelationship.php',
'ManiphestTaskHasDuplicateTaskEdgeType' => 'applications/maniphest/edge/ManiphestTaskHasDuplicateTaskEdgeType.php',
@@ -7401,6 +7402,7 @@
'ManiphestTaskFerretEngine' => 'PhabricatorFerretEngine',
'ManiphestTaskFulltextEngine' => 'PhabricatorFulltextEngine',
'ManiphestTaskGraph' => 'PhabricatorObjectGraph',
+ 'ManiphestTaskGraphController' => 'ManiphestController',
'ManiphestTaskHasCommitEdgeType' => 'PhabricatorEdgeType',
'ManiphestTaskHasCommitRelationship' => 'ManiphestTaskRelationship',
'ManiphestTaskHasDuplicateTaskEdgeType' => 'PhabricatorEdgeType',
diff --git a/src/applications/maniphest/application/PhabricatorManiphestApplication.php b/src/applications/maniphest/application/PhabricatorManiphestApplication.php
--- a/src/applications/maniphest/application/PhabricatorManiphestApplication.php
+++ b/src/applications/maniphest/application/PhabricatorManiphestApplication.php
@@ -55,6 +55,7 @@
'subtask/(?P<id>[1-9]\d*)/' => 'ManiphestTaskSubtaskController',
),
'subpriority/' => 'ManiphestSubpriorityController',
+ 'graph/(?P<id>[1-9]\d*)/' => 'ManiphestTaskGraphController',
),
);
}
diff --git a/src/applications/maniphest/controller/ManiphestController.php b/src/applications/maniphest/controller/ManiphestController.php
--- a/src/applications/maniphest/controller/ManiphestController.php
+++ b/src/applications/maniphest/controller/ManiphestController.php
@@ -61,4 +61,102 @@
return $view;
}
+ final protected function newTaskGraphDropdownMenu(
+ ManiphestTask $task,
+ $has_parents,
+ $has_subtasks,
+ $include_standalone) {
+ $viewer = $this->getViewer();
+
+ $parents_uri = urisprintf(
+ '/?subtaskIDs=%d#R',
+ $task->getID());
+ $parents_uri = $this->getApplicationURI($parents_uri);
+
+ $subtasks_uri = urisprintf(
+ '/?parentIDs=%d#R',
+ $task->getID());
+ $subtasks_uri = $this->getApplicationURI($subtasks_uri);
+
+ $dropdown_menu = id(new PhabricatorActionListView())
+ ->setViewer($viewer)
+ ->addAction(
+ id(new PhabricatorActionView())
+ ->setHref($parents_uri)
+ ->setName(pht('Search Parent Tasks'))
+ ->setDisabled(!$has_parents)
+ ->setIcon('fa-chevron-circle-up'))
+ ->addAction(
+ id(new PhabricatorActionView())
+ ->setHref($subtasks_uri)
+ ->setName(pht('Search Subtasks'))
+ ->setDisabled(!$has_subtasks)
+ ->setIcon('fa-chevron-circle-down'));
+
+ if ($include_standalone) {
+ $standalone_uri = urisprintf('/graph/%d/', $task->getID());
+ $standalone_uri = $this->getApplicationURI($standalone_uri);
+
+ $dropdown_menu->addAction(
+ id(new PhabricatorActionView())
+ ->setHref($standalone_uri)
+ ->setName(pht('View Standalone Graph'))
+ ->setIcon('fa-code-fork'));
+ }
+
+ $graph_menu = id(new PHUIButtonView())
+ ->setTag('a')
+ ->setIcon('fa-search')
+ ->setText(pht('Search...'))
+ ->setDropdownMenu($dropdown_menu);
+
+ return $graph_menu;
+ }
+
+ final protected function newTaskGraphOverflowView(
+ ManiphestTask $task,
+ $overflow_message,
+ $include_standalone) {
+
+ $id = $task->getID();
+
+ if ($include_standalone) {
+ $standalone_uri = $this->getApplicationURI("graph/{$id}/");
+
+ $standalone_link = id(new PHUIButtonView())
+ ->setTag('a')
+ ->setHref($standalone_uri)
+ ->setColor(PHUIButtonView::GREY)
+ ->setIcon('fa-code-fork')
+ ->setText(pht('View Standalone Graph'));
+ } else {
+ $standalone_link = null;
+ }
+
+ $standalone_icon = id(new PHUIIconView())
+ ->setIcon('fa-exclamation-triangle', 'yellow')
+ ->addClass('object-graph-header-icon');
+
+ $standalone_view = phutil_tag(
+ 'div',
+ array(
+ 'class' => 'object-graph-header',
+ ),
+ array(
+ $standalone_link,
+ $standalone_icon,
+ phutil_tag(
+ 'div',
+ array(
+ 'class' => 'object-graph-header-message',
+ ),
+ array(
+ $overflow_message,
+ )),
+ ));
+
+ return $standalone_view;
+ }
+
+
}
diff --git a/src/applications/maniphest/controller/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/ManiphestTaskDetailController.php
--- a/src/applications/maniphest/controller/ManiphestTaskDetailController.php
+++ b/src/applications/maniphest/controller/ManiphestTaskDetailController.php
@@ -80,7 +80,8 @@
$related_tabs = array();
$graph_menu = null;
- $graph_limit = 100;
+ $graph_limit = 200;
+ $overflow_message = null;
$task_graph = id(new ManiphestTaskGraph())
->setViewer($viewer)
->setSeedPHID($task->getPHID())
@@ -96,61 +97,55 @@
$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 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);
+ $overflow_message = pht(
+ 'This task is directly connected to more than %s other tasks. '.
+ 'Use %s to browse parents or subtasks, or %s to show more of the '.
+ 'graph.',
+ new PhutilNumber($graph_limit),
+ phutil_tag('strong', array(), pht('Search...')),
+ phutil_tag('strong', array(), pht('View Standalone Graph')));
+
+ $graph_table = null;
} 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);
+
+ $overflow_message = pht(
+ 'This task is connected to more than %s other tasks. '.
+ 'Only direct parents and subtasks are shown here. Use '.
+ '%s to show more of the graph.',
+ new PhutilNumber($graph_limit),
+ phutil_tag('strong', array(), pht('View Standalone Graph')));
}
+
$graph_table = $task_graph->newGraphTable();
}
- $parents_uri = urisprintf(
- '/?subtaskIDs=%d#R',
- $task->getID());
- $parents_uri = $this->getApplicationURI($parents_uri);
-
- $subtasks_uri = urisprintf(
- '/?parentIDs=%d#R',
- $task->getID());
- $subtasks_uri = $this->getApplicationURI($subtasks_uri);
-
- $dropdown_menu = id(new PhabricatorActionListView())
- ->setViewer($viewer)
- ->addAction(
- id(new PhabricatorActionView())
- ->setHref($parents_uri)
- ->setName(pht('Search Parent Tasks'))
- ->setDisabled(!$has_parents)
- ->setIcon('fa-chevron-circle-up'))
- ->addAction(
- id(new PhabricatorActionView())
- ->setHref($subtasks_uri)
- ->setName(pht('Search Subtasks'))
- ->setDisabled(!$has_subtasks)
- ->setIcon('fa-chevron-circle-down'));
-
- $graph_menu = id(new PHUIButtonView())
- ->setTag('a')
- ->setIcon('fa-search')
- ->setText($search_text)
- ->setDropdownMenu($dropdown_menu);
+ if ($overflow_message) {
+ $overflow_view = $this->newTaskGraphOverflowView(
+ $task,
+ $overflow_message,
+ true);
+
+ $graph_table = array(
+ $overflow_view,
+ $graph_table,
+ );
+ }
+
+ $graph_menu = $this->newTaskGraphDropdownMenu(
+ $task,
+ $has_parents,
+ $has_subtasks,
+ true);
$related_tabs[] = id(new PHUITabView())
->setName(pht('Task Graph'))
diff --git a/src/applications/maniphest/controller/ManiphestTaskGraphController.php b/src/applications/maniphest/controller/ManiphestTaskGraphController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/maniphest/controller/ManiphestTaskGraphController.php
@@ -0,0 +1,125 @@
+<?php
+
+final class ManiphestTaskGraphController
+ extends ManiphestController {
+
+ public function shouldAllowPublic() {
+ return true;
+ }
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $this->getViewer();
+ $id = $request->getURIData('id');
+
+ $task = id(new ManiphestTaskQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->executeOne();
+ if (!$task) {
+ return new Aphront404Response();
+ }
+
+ $crumbs = $this->buildApplicationCrumbs()
+ ->addTextCrumb($task->getMonogram(), $task->getURI())
+ ->addTextCrumb(pht('Graph'))
+ ->setBorder(true);
+
+ $graph_limit = 2000;
+ $overflow_message = null;
+ $task_graph = id(new ManiphestTaskGraph())
+ ->setViewer($viewer)
+ ->setSeedPHID($task->getPHID())
+ ->setLimit($graph_limit)
+ ->loadGraph();
+ if (!$task_graph->isEmpty()) {
+ $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;
+
+ // 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) {
+ $overflow_message = pht(
+ 'This task is directly connected to more than %s other tasks, '.
+ 'which is too many tasks to display. Use %s to browse parents '.
+ 'or subtasks.',
+ new PhutilNumber($graph_limit),
+ phutil_tag('strong', array(), pht('Search...')));
+
+ $graph_table = null;
+ } 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);
+
+ $overflow_message = pht(
+ 'This task is connected to more than %s other tasks. '.
+ 'Only direct parents and subtasks are shown here.',
+ new PhutilNumber($graph_limit));
+ }
+
+ $graph_table = $task_graph->newGraphTable();
+ }
+
+ $graph_menu = $this->newTaskGraphDropdownMenu(
+ $task,
+ $has_parents,
+ $has_subtasks,
+ false);
+ } else {
+ $graph_menu = null;
+ $graph_table = null;
+
+ $overflow_message = pht(
+ 'This task has no parent tasks and no subtasks, so there is no '.
+ 'graph to draw.');
+ }
+
+ if ($overflow_message) {
+ $overflow_view = $this->newTaskGraphOverflowView(
+ $task,
+ $overflow_message,
+ false);
+
+ $graph_table = array(
+ $overflow_view,
+ $graph_table,
+ );
+ }
+
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('Task Graph'));
+
+ if ($graph_menu) {
+ $header->addActionLink($graph_menu);
+ }
+
+ $tab_view = id(new PHUIObjectBoxView())
+ ->setHeader($header)
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+ ->appendChild($graph_table);
+
+ $view = id(new PHUITwoColumnView())
+ ->setFooter($tab_view);
+
+ return $this->newPage()
+ ->setTitle(
+ array(
+ $task->getMonogram(),
+ pht('Graph'),
+ ))
+ ->setCrumbs($crumbs)
+ ->appendChild($view);
+ }
+
+
+}
diff --git a/webroot/rsrc/css/aphront/table-view.css b/webroot/rsrc/css/aphront/table-view.css
--- a/webroot/rsrc/css/aphront/table-view.css
+++ b/webroot/rsrc/css/aphront/table-view.css
@@ -327,3 +327,40 @@
.phui-object-box .aphront-table-view {
border: none;
}
+
+.object-graph-header {
+ padding: 8px 12px;
+ overflow: hidden;
+ background: {$lightyellow};
+ border-bottom: 1px solid {$lightblueborder};
+ vertical-align: middle;
+}
+
+.object-graph-header .object-graph-header-icon {
+ float: left;
+ margin-top: 10px;
+}
+
+.object-graph-header a.button {
+ float: right;
+}
+
+.object-graph-header-message {
+ margin: 8px 200px 8px 20px;
+}
+
+.device .object-graph-header .object-graph-header-icon {
+ display: none;
+}
+
+.device .object-graph-header-message {
+ clear: both;
+ margin: 0;
+}
+
+.device .object-graph-header a.button {
+ margin: 0 auto 12px;
+ display: block;
+ width: 180px;
+ float: none;
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Nov 27, 1:09 AM (21 h, 37 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6790350
Default Alt Text
D20164.diff (15 KB)
Attached To
Mode
D20164: Add a standalone view for the Maniphest task graph
Attached
Detach File
Event Timeline
Log In to Comment