diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 69f8738855..17d71b932a 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -779,7 +779,7 @@ celerity_register_resource_map(array( ), 'javelin-behavior-aphlict-listen' => array( - 'uri' => '/res/204f141a/rsrc/js/application/aphlict/behavior-aphlict-listen.js', + 'uri' => '/res/da96a861/rsrc/js/application/aphlict/behavior-aphlict-listen.js', 'type' => 'js', 'requires' => array( @@ -2314,7 +2314,7 @@ celerity_register_resource_map(array( ), 'phabricator-standard-page-view' => array( - 'uri' => '/res/4e1958d0/rsrc/css/application/base/standard-page-view.css', + 'uri' => '/res/b9c03b7b/rsrc/css/application/base/standard-page-view.css', 'type' => 'css', 'requires' => array( @@ -2569,7 +2569,7 @@ celerity_register_resource_map(array( ), array( 'packages' => array( - '0ba8269e' => + 'e6c01476' => array( 'name' => 'core.pkg.css', 'symbols' => @@ -2598,7 +2598,7 @@ celerity_register_resource_map(array( 21 => 'phabricator-flag-css', 22 => 'aphront-error-view-css', ), - 'uri' => '/res/pkg/0ba8269e/core.pkg.css', + 'uri' => '/res/pkg/e6c01476/core.pkg.css', 'type' => 'css', ), '0c96375e' => @@ -2765,20 +2765,20 @@ celerity_register_resource_map(array( 'reverse' => array( 'aphront-attached-file-view-css' => '7839ae2d', - 'aphront-crumbs-view-css' => '0ba8269e', - 'aphront-dialog-view-css' => '0ba8269e', - 'aphront-error-view-css' => '0ba8269e', - 'aphront-form-view-css' => '0ba8269e', + 'aphront-crumbs-view-css' => 'e6c01476', + 'aphront-dialog-view-css' => 'e6c01476', + 'aphront-error-view-css' => 'e6c01476', + 'aphront-form-view-css' => 'e6c01476', 'aphront-headsup-action-list-view-css' => '32f461a4', - 'aphront-headsup-view-css' => '0ba8269e', - 'aphront-list-filter-view-css' => '0ba8269e', - 'aphront-pager-view-css' => '0ba8269e', - 'aphront-panel-view-css' => '0ba8269e', - 'aphront-side-nav-view-css' => '0ba8269e', - 'aphront-table-view-css' => '0ba8269e', - 'aphront-tokenizer-control-css' => '0ba8269e', - 'aphront-tooltip-css' => '0ba8269e', - 'aphront-typeahead-control-css' => '0ba8269e', + 'aphront-headsup-view-css' => 'e6c01476', + 'aphront-list-filter-view-css' => 'e6c01476', + 'aphront-pager-view-css' => 'e6c01476', + 'aphront-panel-view-css' => 'e6c01476', + 'aphront-side-nav-view-css' => 'e6c01476', + 'aphront-table-view-css' => 'e6c01476', + 'aphront-tokenizer-control-css' => 'e6c01476', + 'aphront-tooltip-css' => 'e6c01476', + 'aphront-typeahead-control-css' => 'e6c01476', 'differential-changeset-view-css' => '32f461a4', 'differential-core-view-css' => '32f461a4', 'differential-inline-comment-editor' => '1662d764', @@ -2844,15 +2844,15 @@ celerity_register_resource_map(array( 'javelin-workflow' => '0c96375e', 'maniphest-task-summary-css' => '7839ae2d', 'maniphest-transaction-detail-css' => '7839ae2d', - 'phabricator-app-buttons-css' => '0ba8269e', + 'phabricator-app-buttons-css' => 'e6c01476', 'phabricator-content-source-view-css' => '32f461a4', - 'phabricator-core-buttons-css' => '0ba8269e', - 'phabricator-core-css' => '0ba8269e', - 'phabricator-directory-css' => '0ba8269e', + 'phabricator-core-buttons-css' => 'e6c01476', + 'phabricator-core-css' => 'e6c01476', + 'phabricator-directory-css' => 'e6c01476', 'phabricator-drag-and-drop-file-upload' => '1662d764', 'phabricator-dropdown-menu' => '0c96375e', - 'phabricator-flag-css' => '0ba8269e', - 'phabricator-jump-nav' => '0ba8269e', + 'phabricator-flag-css' => 'e6c01476', + 'phabricator-jump-nav' => 'e6c01476', 'phabricator-keyboard-shortcut' => '0c96375e', 'phabricator-keyboard-shortcut-manager' => '0c96375e', 'phabricator-menu-item' => '0c96375e', @@ -2860,11 +2860,11 @@ celerity_register_resource_map(array( 'phabricator-paste-file-upload' => '0c96375e', 'phabricator-prefab' => '0c96375e', 'phabricator-project-tag-css' => '7839ae2d', - 'phabricator-remarkup-css' => '0ba8269e', + 'phabricator-remarkup-css' => 'e6c01476', 'phabricator-shaped-request' => '1662d764', - 'phabricator-standard-page-view' => '0ba8269e', + 'phabricator-standard-page-view' => 'e6c01476', 'phabricator-tooltip' => '0c96375e', - 'phabricator-transaction-view-css' => '0ba8269e', - 'syntax-highlighting-css' => '0ba8269e', + 'phabricator-transaction-view-css' => 'e6c01476', + 'syntax-highlighting-css' => 'e6c01476', ), )); diff --git a/src/applications/feed/story/PhabricatorFeedStory.php b/src/applications/feed/story/PhabricatorFeedStory.php index 0018db03e7..672e41eeae 100644 --- a/src/applications/feed/story/PhabricatorFeedStory.php +++ b/src/applications/feed/story/PhabricatorFeedStory.php @@ -22,6 +22,16 @@ abstract class PhabricatorFeedStory { private $hasViewed; private $handles; private $framed; + private $primaryObjectPHID; + + public function setPrimaryObjectPHID($primary_object_phid) { + $this->primaryObjectPHID = $primary_object_phid; + return $this; + } + + public function getPrimaryObjectPHID() { + return $this->primaryObjectPHID; + } final public function __construct(PhabricatorFeedStoryData $data) { $this->data = $data; diff --git a/src/applications/notification/PhabricatorNotificationQuery.php b/src/applications/notification/PhabricatorNotificationQuery.php index 69034b5979..2bf9fc5738 100644 --- a/src/applications/notification/PhabricatorNotificationQuery.php +++ b/src/applications/notification/PhabricatorNotificationQuery.php @@ -19,12 +19,18 @@ final class PhabricatorNotificationQuery extends PhabricatorOffsetPagedQuery { private $userPHID; + private $keys; public function setUserPHID($user_phid) { $this->userPHID = $user_phid; return $this; } + public function withKeys(array $keys) { + $this->keys = $keys; + return $this; + } + public function execute() { if (!$this->userPHID) { throw new Exception("Call setUser() before executing the query"); @@ -37,17 +43,19 @@ final class PhabricatorNotificationQuery extends PhabricatorOffsetPagedQuery { $data = queryfx_all( $conn, - "SELECT story.*, notif.hasViewed FROM %T notif + "SELECT story.*, notif.primaryObjectPHID, notif.hasViewed FROM %T notif JOIN %T story ON notif.chronologicalKey = story.chronologicalKey - WHERE notif.userPHID = %s + %Q ORDER BY notif.chronologicalKey DESC %Q", $notification_table->getTableName(), $story_table->getTableName(), - $this->userPHID, + $this->buildWhereClause($conn), $this->buildLimitClause($conn)); $viewed_map = ipull($data, 'hasViewed', 'chronologicalKey'); + $primary_map = ipull($data, 'primaryObjectPHID', 'chronologicalKey'); + $data = $story_table->loadAllFromArray($data); $stories = array(); @@ -64,9 +72,31 @@ final class PhabricatorNotificationQuery extends PhabricatorOffsetPagedQuery { } $story = newv($class, array($story_data)); $story->setHasViewed($viewed_map[$story->getChronologicalKey()]); + $story->setPrimaryObjectPHID($primary_map[$story->getChronologicalKey()]); $stories[] = $story; } return $stories; } + + private function buildWhereClause(AphrontDatabaseConnection $conn_r) { + $where = array(); + + if ($this->userPHID) { + $where[] = qsprintf( + $conn_r, + 'notif.userPHID = %s', + $this->userPHID); + } + + if ($this->keys) { + $where[] = qsprintf( + $conn_r, + 'notif.chronologicalKey IN (%Ls)', + $this->keys); + } + + return $this->formatWhereClause($where); + } + } diff --git a/src/applications/notification/controller/PhabricatorNotificationIndividualController.php b/src/applications/notification/controller/PhabricatorNotificationIndividualController.php index 916f84d6da..ada8d68c66 100644 --- a/src/applications/notification/controller/PhabricatorNotificationIndividualController.php +++ b/src/applications/notification/controller/PhabricatorNotificationIndividualController.php @@ -23,21 +23,27 @@ final class PhabricatorNotificationIndividualController $request = $this->getRequest(); $user = $request->getUser(); - $chron_key = $request->getStr('key'); - $story = id(new PhabricatorFeedStoryNotification()) - ->loadOneWhere('userPHID = %s AND chronologicalKey = %s', - $user->getPHID(), - $chron_key); + $stories = id(new PhabricatorNotificationQuery()) + ->setUserPHID($user->getPHID()) + ->withKeys(array($request->getStr('key'))) + ->execute(); - if ($story == null) { - $json = array( "pertinent" => false ); - } else { - $json = array( - "pertinent" => true, - "primaryObjectPHID" => $story->getPrimaryObjectPHID(), - ); + if (!$stories) { + return id(new AphrontAjaxResponse())->setContent( + array( + 'pertinent' => false, + )); } - return id(new AphrontAjaxResponse())->setContent($json); + $builder = new PhabricatorNotificationBuilder($stories); + $content = $builder->buildView()->render(); + + $response = array( + 'pertinent' => true, + 'primaryObjectPHID' => head($stories)->getPrimaryObjectPHID(), + 'content' => $content, + ); + + return id(new AphrontAjaxResponse())->setContent($response); } } diff --git a/webroot/rsrc/css/application/base/standard-page-view.css b/webroot/rsrc/css/application/base/standard-page-view.css index 2630273a5c..f3a4b874f2 100644 --- a/webroot/rsrc/css/application/base/standard-page-view.css +++ b/webroot/rsrc/css/application/base/standard-page-view.css @@ -307,7 +307,7 @@ a.handle-disabled { color: #999999; } -.phabricator-notification-unread { +#phabricator-notification-dropdown .phabricator-notification-unread { background: #aacfef; } diff --git a/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js b/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js index 0ef07ffed5..309b28a6e8 100644 --- a/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js +++ b/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js @@ -45,9 +45,14 @@ JX.behavior('aphlict-listen', function(config) { JX.Stratcom.invoke('notification-panel-update', null, {}); + // Show the notification itself. + new JX.Notification() + .setContent(JX.$H(response.content)) + .show(); + + // If the notification affected an object on this page, show a // permanent reload notification if we aren't already. - if ((response.primaryObjectPHID in config.pageObjects) && !showing_reload) { var reload = new JX.Notification()