diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index d311c10ddf..641625a8ec 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -618,6 +618,7 @@ phutil_register_library_map(array( 'ManiphestDefaultTaskExtensions' => 'applications/maniphest/extensions/ManiphestDefaultTaskExtensions.php', 'ManiphestEdgeEventListener' => 'applications/maniphest/event/ManiphestEdgeEventListener.php', 'ManiphestExportController' => 'applications/maniphest/controller/ManiphestExportController.php', + 'ManiphestHovercardEventListener' => 'applications/maniphest/event/ManiphestHovercardEventListener.php', 'ManiphestPeopleMenuEventListener' => 'applications/maniphest/event/ManiphestPeopleMenuEventListener.php', 'ManiphestRemarkupRule' => 'applications/maniphest/remarkup/ManiphestRemarkupRule.php', 'ManiphestReplyHandler' => 'applications/maniphest/ManiphestReplyHandler.php', @@ -2289,6 +2290,7 @@ phutil_register_library_map(array( 'ManiphestDefaultTaskExtensions' => 'ManiphestTaskExtensions', 'ManiphestEdgeEventListener' => 'PhutilEventListener', 'ManiphestExportController' => 'ManiphestController', + 'ManiphestHovercardEventListener' => 'PhutilEventListener', 'ManiphestPeopleMenuEventListener' => 'PhutilEventListener', 'ManiphestRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'ManiphestReplyHandler' => 'PhabricatorMailReplyHandler', diff --git a/src/applications/maniphest/application/PhabricatorApplicationManiphest.php b/src/applications/maniphest/application/PhabricatorApplicationManiphest.php index 038ec46bf4..7d1e1d7e4f 100644 --- a/src/applications/maniphest/application/PhabricatorApplicationManiphest.php +++ b/src/applications/maniphest/application/PhabricatorApplicationManiphest.php @@ -39,6 +39,7 @@ final class PhabricatorApplicationManiphest extends PhabricatorApplication { public function getEventListeners() { return array( new ManiphestPeopleMenuEventListener(), + new ManiphestHovercardEventListener(), ); } diff --git a/src/applications/maniphest/event/ManiphestHovercardEventListener.php b/src/applications/maniphest/event/ManiphestHovercardEventListener.php new file mode 100644 index 0000000000..48a1bc9015 --- /dev/null +++ b/src/applications/maniphest/event/ManiphestHovercardEventListener.php @@ -0,0 +1,117 @@ +listen(PhabricatorEventType::TYPE_UI_DIDRENDERHOVERCARD); + } + + public function handleEvent(PhutilEvent $event) { + switch ($event->getType()) { + case PhabricatorEventType::TYPE_UI_DIDRENDERHOVERCARD: + $this->handleHovercardEvent($event); + break; + } + } + + private function handleHovercardEvent(PhutilEvent $event) { + $viewer = $event->getUser(); + $hovercard = $event->getValue('hovercard'); + $handle = $event->getValue('handle'); + $phid = $handle->getPHID(); + $task = $event->getValue('object'); + + if (!($task instanceof ManiphestTask)) { + return; + } + + // Fun with "Unbeta Pholio", hua hua + $e_dep_on = PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK; + $e_dep_by = PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK; + + $edge_query = id(new PhabricatorEdgeQuery()) + ->withSourcePHIDs(array($phid)) + ->withEdgeTypes( + array( + $e_dep_on, + $e_dep_by, + )); + $edges = idx($edge_query->execute(), $phid); + $edge_phids = $edge_query->getDestinationPHIDs(); + + $owner_phid = $task->getOwnerPHID(); + $project_phids = $task->getProjectPHIDs(); + + $phids = array_filter(array_merge( + array($owner_phid), + $edge_phids, + $project_phids)); + + $viewer_handles = $this->loadHandles($phids, $viewer); + + $hovercard->setTitle(pht('T%d', $task->getID())) + ->setDetail($task->getTitle()); + + $owner = phutil_tag('em', array(), pht('None')); + if ($owner_phid) { + $owner = $viewer_handles[$owner_phid]->renderLink(); + } + + $hovercard->addField(pht('Assigned to'), $owner); + if ($project_phids) { + $hovercard->addField(pht('Projects'), + $this->renderHandlesForPHIDs($project_phids, $viewer_handles)); + } + + if ($edge_phids) { + $edge_types = array( + PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK + => pht('Dependent Tasks'), + PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK + => pht('Depends On'), + ); + + $max_count = 6; + foreach ($edge_types as $edge_type => $edge_name) { + if ($edges[$edge_type]) { + // TODO: This can be made more sophisticated. We still load all + // edges into memory. Only load the ones we need. + $edge_overflow = array(); + if (count($edges[$edge_type]) > $max_count) { + $edges[$edge_type] = array_slice($edges[$edge_type], 0, 6, true); + $edge_overflow = ', ...'; + } + + $hovercard->addField( + $edge_name, + $this->renderHandlesForPHIDs( + array_keys($edges[$edge_type]), + $viewer_handles) + ->appendHTML($edge_overflow)); + } + } + } + + $hovercard->addTag(ManiphestView::renderTagForTask($task)); + + $event->setValue('hovercard', $hovercard); + } + + protected function loadHandles(array $phids, $viewer) { + return id(new PhabricatorObjectHandleData($phids)) + ->setViewer($viewer) + ->loadHandles(); + } + + protected function renderHandlesForPHIDs(array $phids, + array $handles, $glue = ', ') { + + $items = array(); + foreach ($phids as $phid) { + $items[] = $handles[$phid]->renderLink(); + } + + return phutil_implode_html($glue, $items); + } + +} diff --git a/src/infrastructure/events/constant/PhabricatorEventType.php b/src/infrastructure/events/constant/PhabricatorEventType.php index 6ccc84dd37..20e7b688ad 100644 --- a/src/infrastructure/events/constant/PhabricatorEventType.php +++ b/src/infrastructure/events/constant/PhabricatorEventType.php @@ -31,5 +31,7 @@ final class PhabricatorEventType extends PhutilEventType { const TYPE_UI_DIDRENDEROBJECTS = 'ui.didRenderObjects'; const TYPE_UI_WILLRENDERPROPERTIES = 'ui.willRenderProperties'; + const TYPE_UI_DIDRENDERHOVERCARD = 'ui.didRenderHovercard'; + const TYPE_PEOPLE_DIDRENDERMENU = 'people.didRenderMenu'; }