diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index fd82a18d6c..1fe1cc8b1f 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -231,6 +231,7 @@ phutil_register_library_map(array( 'ConpherenceEditor' => 'applications/conpherence/editor/ConpherenceEditor.php', 'ConpherenceFileWidgetView' => 'applications/conpherence/view/ConpherenceFileWidgetView.php', 'ConpherenceFormDragAndDropUploadControl' => 'applications/conpherence/view/ConpherenceFormDragAndDropUploadControl.php', + 'ConpherenceHovercardEventListener' => 'applications/conpherence/events/ConpherenceHovercardEventListener.php', 'ConpherenceImageData' => 'applications/conpherence/constants/ConpherenceImageData.php', 'ConpherenceLayoutView' => 'applications/conpherence/view/ConpherenceLayoutView.php', 'ConpherenceListController' => 'applications/conpherence/controller/ConpherenceListController.php', @@ -330,6 +331,7 @@ phutil_register_library_map(array( 'DifferentialFreeformFieldSpecification' => 'applications/differential/field/specification/DifferentialFreeformFieldSpecification.php', 'DifferentialGitSVNIDFieldSpecification' => 'applications/differential/field/specification/DifferentialGitSVNIDFieldSpecification.php', 'DifferentialHostFieldSpecification' => 'applications/differential/field/specification/DifferentialHostFieldSpecification.php', + 'DifferentialHovercardEventListener' => 'applications/differential/events/DifferentialHovercardEventListener.php', 'DifferentialHunk' => 'applications/differential/storage/DifferentialHunk.php', 'DifferentialHunkParser' => 'applications/differential/parser/DifferentialHunkParser.php', 'DifferentialHunkParserTestCase' => 'applications/differential/parser/__tests__/DifferentialHunkParserTestCase.php', @@ -437,6 +439,7 @@ phutil_register_library_map(array( 'DiffusionHistoryQuery' => 'applications/diffusion/query/history/DiffusionHistoryQuery.php', 'DiffusionHistoryTableView' => 'applications/diffusion/view/DiffusionHistoryTableView.php', 'DiffusionHomeController' => 'applications/diffusion/controller/DiffusionHomeController.php', + 'DiffusionHovercardEventListener' => 'applications/diffusion/events/DiffusionHovercardEventListener.php', 'DiffusionInlineCommentController' => 'applications/diffusion/controller/DiffusionInlineCommentController.php', 'DiffusionInlineCommentPreviewController' => 'applications/diffusion/controller/DiffusionInlineCommentPreviewController.php', 'DiffusionLastModifiedController' => 'applications/diffusion/controller/DiffusionLastModifiedController.php', @@ -1188,6 +1191,7 @@ phutil_register_library_map(array( 'PhabricatorPasteViewController' => 'applications/paste/controller/PhabricatorPasteViewController.php', 'PhabricatorPeopleController' => 'applications/people/controller/PhabricatorPeopleController.php', 'PhabricatorPeopleEditController' => 'applications/people/controller/PhabricatorPeopleEditController.php', + 'PhabricatorPeopleHovercardEventListener' => 'applications/people/event/PhabricatorPeopleHovercardEventListener.php', 'PhabricatorPeopleLdapController' => 'applications/people/controller/PhabricatorPeopleLdapController.php', 'PhabricatorPeopleListController' => 'applications/people/controller/PhabricatorPeopleListController.php', 'PhabricatorPeopleLogsController' => 'applications/people/controller/PhabricatorPeopleLogsController.php', @@ -1954,6 +1958,7 @@ phutil_register_library_map(array( 'ConpherenceEditor' => 'PhabricatorApplicationTransactionEditor', 'ConpherenceFileWidgetView' => 'ConpherenceWidgetView', 'ConpherenceFormDragAndDropUploadControl' => 'AphrontFormControl', + 'ConpherenceHovercardEventListener' => 'PhutilEventListener', 'ConpherenceImageData' => 'ConpherenceConstants', 'ConpherenceLayoutView' => 'AphrontView', 'ConpherenceListController' => 'ConpherenceController', @@ -2049,6 +2054,7 @@ phutil_register_library_map(array( 'DifferentialFreeformFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialGitSVNIDFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialHostFieldSpecification' => 'DifferentialFieldSpecification', + 'DifferentialHovercardEventListener' => 'PhutilEventListener', 'DifferentialHunk' => 'DifferentialDAO', 'DifferentialHunkParserTestCase' => 'PhabricatorTestCase', 'DifferentialHunkTestCase' => 'ArcanistPhutilTestCase', @@ -2150,6 +2156,7 @@ phutil_register_library_map(array( 'DiffusionHistoryQuery' => 'DiffusionQuery', 'DiffusionHistoryTableView' => 'DiffusionView', 'DiffusionHomeController' => 'DiffusionController', + 'DiffusionHovercardEventListener' => 'PhutilEventListener', 'DiffusionInlineCommentController' => 'PhabricatorInlineCommentController', 'DiffusionInlineCommentPreviewController' => 'PhabricatorInlineCommentPreviewController', 'DiffusionLastModifiedController' => 'DiffusionController', @@ -2859,6 +2866,7 @@ phutil_register_library_map(array( 'PhabricatorPasteViewController' => 'PhabricatorPasteController', 'PhabricatorPeopleController' => 'PhabricatorController', 'PhabricatorPeopleEditController' => 'PhabricatorPeopleController', + 'PhabricatorPeopleHovercardEventListener' => 'PhutilEventListener', 'PhabricatorPeopleLdapController' => 'PhabricatorPeopleController', 'PhabricatorPeopleListController' => 'PhabricatorPeopleController', 'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController', diff --git a/src/applications/conpherence/application/PhabricatorApplicationConpherence.php b/src/applications/conpherence/application/PhabricatorApplicationConpherence.php index 76bfaf88f2..013fdf8c95 100644 --- a/src/applications/conpherence/application/PhabricatorApplicationConpherence.php +++ b/src/applications/conpherence/application/PhabricatorApplicationConpherence.php @@ -36,6 +36,7 @@ final class PhabricatorApplicationConpherence extends PhabricatorApplication { public function getEventListeners() { return array( new ConpherencePeopleMenuEventListener(), + new ConpherenceHovercardEventListener(), ); } diff --git a/src/applications/conpherence/events/ConpherenceHovercardEventListener.php b/src/applications/conpherence/events/ConpherenceHovercardEventListener.php new file mode 100644 index 0000000000..8e187280c8 --- /dev/null +++ b/src/applications/conpherence/events/ConpherenceHovercardEventListener.php @@ -0,0 +1,42 @@ +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($event) { + $hovercard = $event->getValue('hovercard'); + $user = $event->getValue('object'); + + if (!($user instanceof PhabricatorUser)) { + return; + } + + $conpherence_uri = new PhutilURI( + '/conpherence/new/?participant='.$user->getPHID()); + $name = pht('Start a Conpherence'); + $hovercard->addAction($name, $conpherence_uri, true); + + $event->setValue('hovercard', $hovercard); + } + +} + diff --git a/src/applications/differential/application/PhabricatorApplicationDifferential.php b/src/applications/differential/application/PhabricatorApplicationDifferential.php index 37509c221f..96a3873558 100644 --- a/src/applications/differential/application/PhabricatorApplicationDifferential.php +++ b/src/applications/differential/application/PhabricatorApplicationDifferential.php @@ -30,7 +30,8 @@ final class PhabricatorApplicationDifferential extends PhabricatorApplication { public function getEventListeners() { return array( - new DifferentialPeopleMenuEventListener() + new DifferentialPeopleMenuEventListener(), + new DifferentialHovercardEventListener(), ); } diff --git a/src/applications/differential/events/DifferentialHovercardEventListener.php b/src/applications/differential/events/DifferentialHovercardEventListener.php new file mode 100644 index 0000000000..f68ce8f59e --- /dev/null +++ b/src/applications/differential/events/DifferentialHovercardEventListener.php @@ -0,0 +1,81 @@ +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($event) { + $viewer = $event->getUser(); + $hovercard = $event->getValue('hovercard'); + $object_handle = $event->getValue('handle'); + $phid = $object_handle->getPHID(); + $rev = $event->getValue('object'); + + if (!($rev instanceof DifferentialRevision)) { + return; + } + + $rev->loadRelationships(); + $reviewer_phids = $rev->getReviewers(); + $e_task = PhabricatorEdgeConfig::TYPE_DREV_HAS_RELATED_TASK; + $edge_query = id(new PhabricatorEdgeQuery()) + ->withSourcePHIDs(array($phid)) + ->withEdgeTypes( + array( + $e_task, + )); + $edge_query->execute(); + $tasks = $edge_query->getDestinationPHIDs(); + + $phids = array_merge( + array( + $rev->getAuthorPHID(), + ), + $reviewer_phids, + $tasks); + + $handles = id(new PhabricatorObjectHandleData($phids)) + ->setViewer($viewer) + ->loadHandles(); + + $hovercard->setTitle('D'.$rev->getID()); + $hovercard->setDetail($rev->getTitle()); + + $hovercard->addField(pht('Author'), + $handles[$rev->getAuthorPHID()]->renderLink()); + + $hovercard->addField(pht('Date'), + phabricator_datetime($rev->getDateModified(), $viewer)); + + $hovercard->addField(pht('Reviewers'), + implode_selected_handle_links(', ', $handles, $reviewer_phids)); + + if ($tasks) { + $hovercard->addField(pht('Task(s)', count($tasks)), + implode_selected_handle_links(', ', $handles, $tasks)); + } + + if ($rev->getSummary()) { + $hovercard->addField(pht('Summary'), + phutil_utf8_shorten($rev->getSummary(), 120)); + } + + $hovercard->addTag( + DifferentialRevisionDetailView::renderTagForRevision($rev)); + $hovercard->setColor(PhabricatorActionHeaderView::HEADER_BLUE); + + $event->setValue('hovercard', $hovercard); + } + +} + diff --git a/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php b/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php index 8db6c43d6a..0f83f3f44a 100644 --- a/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php +++ b/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php @@ -26,7 +26,8 @@ final class PhabricatorApplicationDiffusion extends PhabricatorApplication { public function getEventListeners() { return array( - new DiffusionPeopleMenuEventListener() + new DiffusionPeopleMenuEventListener(), + new DiffusionHovercardEventListener(), ); } diff --git a/src/applications/diffusion/events/DiffusionHovercardEventListener.php b/src/applications/diffusion/events/DiffusionHovercardEventListener.php new file mode 100644 index 0000000000..a4de6ecb06 --- /dev/null +++ b/src/applications/diffusion/events/DiffusionHovercardEventListener.php @@ -0,0 +1,73 @@ +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($event) { + $viewer = $event->getUser(); + $hovercard = $event->getValue('hovercard'); + $object_handle = $event->getValue('handle'); + $phid = $object_handle->getPHID(); + $commit = $event->getValue('object'); + + if (!($commit instanceof PhabricatorRepositoryCommit)) { + return; + } + + $commit_data = $commit->loadCommitData(); + $revision = $commit_data->getCommitDetail('differential.revisionPHID'); + + $author = $commit->getAuthorPHID(); + + $phids = array_filter(array( + $revision, + $author, + )); + + $handles = id(new PhabricatorObjectHandleData($phids)) + ->setViewer($viewer) + ->loadHandles(); + + if ($author) { + $author = $handles[$author]->renderLink(); + } else { + $author = phutil_tag('em', array(), $commit_data->getAuthorName()); + } + + $hovercard->setTitle($object_handle->getName()); + $hovercard->setDetail($commit->getSummary()); + + $hovercard->addField(pht('Author'), $author); + $hovercard->addField(pht('Date'), + phabricator_date($commit->getEpoch(), $viewer)); + + if ($commit->getAuditStatus() != + PhabricatorAuditCommitStatusConstants::NONE) { + + $hovercard->addField(pht('Audit Status'), + PhabricatorAuditCommitStatusConstants::getStatusName( + $commit->getAuditStatus())); + } + + if ($revision) { + $rev_handle = $handles[$revision]; + $hovercard->addField(pht('Revision'), $rev_handle->renderLink()); + } + $hovercard->setColor(PhabricatorActionHeaderView::HEADER_YELLOW); + + $event->setValue('hovercard', $hovercard); + } + +} + diff --git a/src/applications/people/application/PhabricatorApplicationPeople.php b/src/applications/people/application/PhabricatorApplicationPeople.php index 798472a0d9..25071b53d8 100644 --- a/src/applications/people/application/PhabricatorApplicationPeople.php +++ b/src/applications/people/application/PhabricatorApplicationPeople.php @@ -30,6 +30,12 @@ final class PhabricatorApplicationPeople extends PhabricatorApplication { return false; } + public function getEventListeners() { + return array( + new PhabricatorPeopleHovercardEventListener(), + ); + } + public function getRoutes() { return array( '/people/' => array( diff --git a/src/applications/people/event/PhabricatorPeopleHovercardEventListener.php b/src/applications/people/event/PhabricatorPeopleHovercardEventListener.php new file mode 100644 index 0000000000..af2d0c7a74 --- /dev/null +++ b/src/applications/people/event/PhabricatorPeopleHovercardEventListener.php @@ -0,0 +1,70 @@ +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($event) { + $viewer = $event->getUser(); + $hovercard = $event->getValue('hovercard'); + $object_handle = $event->getValue('handle'); + $phid = $object_handle->getPHID(); + $user = $event->getValue('object'); + + if (!($user instanceof PhabricatorUser)) { + return; + } + + $profile = $user->loadUserProfile(); + + $hovercard->setTitle($user->getUsername()); + $hovercard->setDetail(pht('%s - %s.', $user->getRealname(), + nonempty($profile->getTitle(), + pht('No title was found befitting of this rare specimen')))); + + $hovercard->addField(pht('User since'), + phabricator_date($user->getDateCreated(), $user)); + + if ($user->getIsDisabled()) { + $hovercard->addTag(id(new PhabricatorTagView()) + ->setBackgroundColor(PhabricatorTagView::COLOR_BLACK) + ->setName(pht('Disabled')) + ->setType(PhabricatorTagView::TYPE_STATE)); + } else { + $statuses = id(new PhabricatorUserStatus())->loadCurrentStatuses( + array($user->getPHID())); + if ($statuses) { + $current_status = reset($statuses); + $hovercard->addField(pht('Status'), + $current_status->getDescription()); + $hovercard->addTag(id(new PhabricatorTagView()) + ->setName($current_status->getHumanStatus()) + ->setBackgroundColor(PhabricatorTagView::COLOR_BLUE) + ->setType(PhabricatorTagView::TYPE_STATE)); + } else { + $hovercard->addField(pht('Status'), pht('Available')); + } + } + + if ($profile->getBlurb()) { + $hovercard->addField(pht('Blurb'), + phutil_utf8_shorten($profile->getBlurb(), 120)); + } + $hovercard->setColor(PhabricatorActionHeaderView::HEADER_RED); + + $event->setValue('hovercard', $hovercard); + } + + +} diff --git a/src/infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php b/src/infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php index 1b3640906c..009b2e6ee0 100644 --- a/src/infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php +++ b/src/infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php @@ -15,6 +15,7 @@ abstract class PhabricatorBaseEnglishTranslation ), 'file(s)' => array('file', 'files'), 'Maniphest Task(s)' => array('Maniphest Task', 'Maniphest Tasks'), + 'Task(s)' => array('Task', 'Tasks'), 'Please fix these errors and try again.' => array( 'Please fix this error and try again.',