@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Adds the UI dropdown panel

Summary:
Add a dropdown to display notificaitons. Right now
there is nothing real time about it, but we do update the panel
when the user clicks. This panel is only displayed if the
install has notifications enabled and you have them enabled in
your preferences (not using them by default).

Test Plan: Turn off notifications for user1, left them on for user2. Did things from user1 and from user2 on task both were cc'd on. user2 recieved all notifications, user1 recieved nothing. Made new user, made sure everything was switched off by default.

Reviewers: epriestley, btrahan

Reviewed By: epriestley

CC: keebuhm, ddfisher, aran, Korvin

Differential Revision: https://secure.phabricator.com/D2703

authored by

John-Ashton Allen and committed by
epriestley
a11deec4 a57f5d15

+274 -27
+40 -26
src/__celerity_resource_map__.php
··· 756 756 ), 757 757 'disk' => '/rsrc/js/javelin/lib/behavior.js', 758 758 ), 759 + 'javelin-behavior-aphlict-dropdown' => 760 + array( 761 + 'uri' => '/res/d0025c08/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js', 762 + 'type' => 'js', 763 + 'requires' => 764 + array( 765 + 0 => 'javelin-behavior', 766 + 1 => 'javelin-aphlict', 767 + 2 => 'javelin-util', 768 + 3 => 'javelin-request', 769 + 4 => 'javelin-stratcom', 770 + ), 771 + 'disk' => '/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js', 772 + ), 759 773 'javelin-behavior-aphlict-listen' => 760 774 array( 761 775 'uri' => '/res/6388e057/rsrc/js/application/aphlict/behavior-aphlict-listen.js', ··· 2242 2256 ), 2243 2257 'phabricator-standard-page-view' => 2244 2258 array( 2245 - 'uri' => '/res/07d5f4cb/rsrc/css/application/base/standard-page-view.css', 2259 + 'uri' => '/res/479161fe/rsrc/css/application/base/standard-page-view.css', 2246 2260 'type' => 'css', 2247 2261 'requires' => 2248 2262 array( ··· 2497 2511 ), array( 2498 2512 'packages' => 2499 2513 array( 2500 - '4984f83f' => 2514 + 'f6b9a4d4' => 2501 2515 array( 2502 2516 'name' => 'core.pkg.css', 2503 2517 'symbols' => ··· 2526 2540 21 => 'phabricator-flag-css', 2527 2541 22 => 'aphront-error-view-css', 2528 2542 ), 2529 - 'uri' => '/res/pkg/4984f83f/core.pkg.css', 2543 + 'uri' => '/res/pkg/f6b9a4d4/core.pkg.css', 2530 2544 'type' => 'css', 2531 2545 ), 2532 2546 '0c96375e' => ··· 2693 2707 'reverse' => 2694 2708 array( 2695 2709 'aphront-attached-file-view-css' => '7839ae2d', 2696 - 'aphront-crumbs-view-css' => '4984f83f', 2697 - 'aphront-dialog-view-css' => '4984f83f', 2698 - 'aphront-error-view-css' => '4984f83f', 2699 - 'aphront-form-view-css' => '4984f83f', 2710 + 'aphront-crumbs-view-css' => 'f6b9a4d4', 2711 + 'aphront-dialog-view-css' => 'f6b9a4d4', 2712 + 'aphront-error-view-css' => 'f6b9a4d4', 2713 + 'aphront-form-view-css' => 'f6b9a4d4', 2700 2714 'aphront-headsup-action-list-view-css' => '32f461a4', 2701 - 'aphront-headsup-view-css' => '4984f83f', 2702 - 'aphront-list-filter-view-css' => '4984f83f', 2703 - 'aphront-pager-view-css' => '4984f83f', 2704 - 'aphront-panel-view-css' => '4984f83f', 2705 - 'aphront-side-nav-view-css' => '4984f83f', 2706 - 'aphront-table-view-css' => '4984f83f', 2707 - 'aphront-tokenizer-control-css' => '4984f83f', 2708 - 'aphront-tooltip-css' => '4984f83f', 2709 - 'aphront-typeahead-control-css' => '4984f83f', 2715 + 'aphront-headsup-view-css' => 'f6b9a4d4', 2716 + 'aphront-list-filter-view-css' => 'f6b9a4d4', 2717 + 'aphront-pager-view-css' => 'f6b9a4d4', 2718 + 'aphront-panel-view-css' => 'f6b9a4d4', 2719 + 'aphront-side-nav-view-css' => 'f6b9a4d4', 2720 + 'aphront-table-view-css' => 'f6b9a4d4', 2721 + 'aphront-tokenizer-control-css' => 'f6b9a4d4', 2722 + 'aphront-tooltip-css' => 'f6b9a4d4', 2723 + 'aphront-typeahead-control-css' => 'f6b9a4d4', 2710 2724 'differential-changeset-view-css' => '32f461a4', 2711 2725 'differential-core-view-css' => '32f461a4', 2712 2726 'differential-inline-comment-editor' => '86f654e2', ··· 2772 2786 'javelin-workflow' => '0c96375e', 2773 2787 'maniphest-task-summary-css' => '7839ae2d', 2774 2788 'maniphest-transaction-detail-css' => '7839ae2d', 2775 - 'phabricator-app-buttons-css' => '4984f83f', 2789 + 'phabricator-app-buttons-css' => 'f6b9a4d4', 2776 2790 'phabricator-content-source-view-css' => '32f461a4', 2777 - 'phabricator-core-buttons-css' => '4984f83f', 2778 - 'phabricator-core-css' => '4984f83f', 2779 - 'phabricator-directory-css' => '4984f83f', 2791 + 'phabricator-core-buttons-css' => 'f6b9a4d4', 2792 + 'phabricator-core-css' => 'f6b9a4d4', 2793 + 'phabricator-directory-css' => 'f6b9a4d4', 2780 2794 'phabricator-drag-and-drop-file-upload' => '86f654e2', 2781 2795 'phabricator-dropdown-menu' => '0c96375e', 2782 - 'phabricator-flag-css' => '4984f83f', 2783 - 'phabricator-jump-nav' => '4984f83f', 2796 + 'phabricator-flag-css' => 'f6b9a4d4', 2797 + 'phabricator-jump-nav' => 'f6b9a4d4', 2784 2798 'phabricator-keyboard-shortcut' => '0c96375e', 2785 2799 'phabricator-keyboard-shortcut-manager' => '0c96375e', 2786 2800 'phabricator-menu-item' => '0c96375e', ··· 2788 2802 'phabricator-paste-file-upload' => '0c96375e', 2789 2803 'phabricator-prefab' => '0c96375e', 2790 2804 'phabricator-project-tag-css' => '7839ae2d', 2791 - 'phabricator-remarkup-css' => '4984f83f', 2805 + 'phabricator-remarkup-css' => 'f6b9a4d4', 2792 2806 'phabricator-shaped-request' => '86f654e2', 2793 - 'phabricator-standard-page-view' => '4984f83f', 2807 + 'phabricator-standard-page-view' => 'f6b9a4d4', 2794 2808 'phabricator-tooltip' => '0c96375e', 2795 - 'phabricator-transaction-view-css' => '4984f83f', 2796 - 'syntax-highlighting-css' => '4984f83f', 2809 + 'phabricator-transaction-view-css' => 'f6b9a4d4', 2810 + 'syntax-highlighting-css' => 'f6b9a4d4', 2797 2811 ), 2798 2812 ));
+14
src/__phutil_library_map__.php
··· 525 525 'ManiphestView' => 'applications/maniphest/view/ManiphestView.php', 526 526 'MetaMTAConstants' => 'applications/metamta/constants/MetaMTAConstants.php', 527 527 'MetaMTANotificationType' => 'applications/metamta/constants/MetaMTANotificationType.php', 528 + 'NotificationMessage' => 'applications/notification/constants/message/NotificationMessage.php', 529 + 'NotificationPathname' => 'applications/notification/constants/pathname/NotificationPathname.php', 530 + 'NotificationType' => 'applications/notification/constants/type/NotificationType.php', 528 531 'OwnersPackageReplyHandler' => 'applications/owners/OwnersPackageReplyHandler.php', 529 532 'PackageCreateMail' => 'applications/owners/mail/PackageCreateMail.php', 530 533 'PackageDeleteMail' => 'applications/owners/mail/PackageDeleteMail.php', ··· 735 738 'PhabricatorMustVerifyEmailController' => 'applications/auth/controller/PhabricatorMustVerifyEmailController.php', 736 739 'PhabricatorMySQLFileStorageEngine' => 'applications/files/engine/PhabricatorMySQLFileStorageEngine.php', 737 740 'PhabricatorNotificationBuilder' => 'applications/notification/builder/PhabricatorNotificationBuilder.php', 741 + 'PhabricatorNotificationConstants' => 'applications/notification/constants/base/PhabricatorNotificationConstants.php', 738 742 'PhabricatorNotificationController' => 'applications/notification/controller/PhabricatorNotificationController.php', 743 + 'PhabricatorNotificationPanelController' => 'applications/notification/controller/PhabricatorNotificationPanelController.php', 739 744 'PhabricatorNotificationQuery' => 'applications/notification/PhabricatorNotificationQuery.php', 745 + 'PhabricatorNotificationStory' => 'applications/notification/base/PhabricatorNotificationStory.php', 746 + 'PhabricatorNotificationStoryTypeConstants' => 'applications/notification/constants/story/PhabricatorNotificationStoryTypeConstants.php', 740 747 'PhabricatorNotificationStoryView' => 'applications/notification/view/PhabricatorNotificationStoryView.php', 741 748 'PhabricatorNotificationTestController' => 'applications/notification/controller/PhabricatorNotificationTestController.php', 742 749 'PhabricatorNotificationView' => 'applications/notification/view/PhabricatorNotificationView.php', ··· 972 979 'PhabricatorUserEmailPreferenceSettingsPanelController' => 'applications/people/controller/settings/panels/PhabricatorUserEmailPreferenceSettingsPanelController.php', 973 980 'PhabricatorUserEmailSettingsPanelController' => 'applications/people/controller/settings/panels/PhabricatorUserEmailSettingsPanelController.php', 974 981 'PhabricatorUserLog' => 'applications/people/storage/PhabricatorUserLog.php', 982 + 'PhabricatorUserNotificationPreferenceSettingsPanelController' => 'applications/people/controller/settings/panels/PhabricatorUserNotificationPreferenceSettingsPanelController.php', 975 983 'PhabricatorUserOAuthInfo' => 'applications/people/storage/PhabricatorUserOAuthInfo.php', 976 984 'PhabricatorUserOAuthSettingsPanelController' => 'applications/people/controller/settings/panels/PhabricatorUserOAuthSettingsPanelController.php', 977 985 'PhabricatorUserPasswordSettingsPanelController' => 'applications/people/controller/settings/panels/PhabricatorUserPasswordSettingsPanelController.php', ··· 1518 1526 'ManiphestTransactionType' => 'ManiphestConstants', 1519 1527 'ManiphestView' => 'AphrontView', 1520 1528 'MetaMTANotificationType' => 'MetaMTAConstants', 1529 + 'NotificationMessage' => 'PhabricatorNotificationConstants', 1530 + 'NotificationPathname' => 'PhabricatorNotificationConstants', 1531 + 'NotificationType' => 'PhabricatorNotificationConstants', 1521 1532 'OwnersPackageReplyHandler' => 'PhabricatorMailReplyHandler', 1522 1533 'PackageCreateMail' => 'PackageMail', 1523 1534 'PackageDeleteMail' => 'PackageMail', ··· 1697 1708 'PhabricatorMustVerifyEmailController' => 'PhabricatorAuthController', 1698 1709 'PhabricatorMySQLFileStorageEngine' => 'PhabricatorFileStorageEngine', 1699 1710 'PhabricatorNotificationController' => 'PhabricatorController', 1711 + 'PhabricatorNotificationPanelController' => 'PhabricatorNotificationController', 1712 + 'PhabricatorNotificationStoryTypeConstants' => 'PhabricatorNotificationConstants', 1700 1713 'PhabricatorNotificationStoryView' => 'PhabricatorNotificationView', 1701 1714 'PhabricatorNotificationTestController' => 'PhabricatorNotificationController', 1702 1715 'PhabricatorNotificationView' => 'AphrontView', ··· 1898 1911 'PhabricatorUserEmailPreferenceSettingsPanelController' => 'PhabricatorUserSettingsPanelController', 1899 1912 'PhabricatorUserEmailSettingsPanelController' => 'PhabricatorUserSettingsPanelController', 1900 1913 'PhabricatorUserLog' => 'PhabricatorUserDAO', 1914 + 'PhabricatorUserNotificationPreferenceSettingsPanelController' => 'PhabricatorUserSettingsPanelController', 1901 1915 'PhabricatorUserOAuthInfo' => 'PhabricatorUserDAO', 1902 1916 'PhabricatorUserOAuthSettingsPanelController' => 'PhabricatorUserSettingsPanelController', 1903 1917 'PhabricatorUserPasswordSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
+1
src/aphront/configuration/AphrontDefaultApplicationConfiguration.php
··· 422 422 ), 423 423 424 424 '/notification/test/' => 'PhabricatorNotificationTestController', 425 + '/notification/panel/' => 'PhabricatorNotificationPanelController', 425 426 '/flag/' => array( 426 427 '' => 'PhabricatorFlagListController', 427 428 'view/(?P<view>[^/]+)/' => 'PhabricatorFlagListController',
+1
src/applications/notification/builder/PhabricatorNotificationBuilder.php
··· 39 39 40 40 $null_view = new AphrontNullView(); 41 41 42 + //TODO ADD NOTIFICATIONS HEADER 42 43 foreach ($stories as $story) { 43 44 $story->setHandles($handles); 44 45 $view = $story->renderNotificationView();
+44
src/applications/notification/controller/PhabricatorNotificationPanelController.php
··· 1 + <?php 2 + 3 + /* 4 + * Copyright 2012 Facebook, Inc. 5 + * 6 + * Licensed under the Apache License, Version 2.0 (the "License"); 7 + * you may not use this file except in compliance with the License. 8 + * You may obtain a copy of the License at 9 + * 10 + * http://www.apache.org/licenses/LICENSE-2.0 11 + * 12 + * Unless required by applicable law or agreed to in writing, software 13 + * distributed under the License is distributed on an "AS IS" BASIS, 14 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 + * See the License for the specific language governing permissions and 16 + * limitations under the License. 17 + */ 18 + 19 + final class PhabricatorNotificationPanelController 20 + extends PhabricatorNotificationController { 21 + 22 + public function processRequest() { 23 + 24 + $request = $this->getRequest(); 25 + $user = $request->getUser(); 26 + 27 + $query = new PhabricatorNotificationQuery(); 28 + $query->setUserPHID($user->getPHID()); 29 + $query->setLimit(15); 30 + 31 + $stories = $query->execute(); 32 + 33 + $builder = new PhabricatorNotificationBuilder($stories); 34 + $notifications_view = $builder->buildView(); 35 + 36 + $json = array( 37 + "content" => $stories ? 38 + $notifications_view->render() : 39 + "<b>You currently have no notifications<b>", 40 + ); 41 + 42 + return id(new AphrontAjaxResponse())->setContent($json); 43 + } 44 + }
+18
src/applications/notification/storage/PhabricatorFeedStoryNotification.php
··· 54 54 } 55 55 } 56 56 57 + /* should only be called when notifications are enabled */ 58 + public function countUnread( 59 + PhabricatorUser $user) { 60 + 61 + $conn = $this->establishConnection('r'); 62 + 63 + $data = queryfx_one( 64 + $conn, 65 + "SELECT COUNT(*) as count 66 + FROM %T 67 + WHERE userPHID = %s 68 + AND hasViewed=0", 69 + $this->getTableName(), 70 + $user->getPHID()); 71 + 72 + return $data['count']; 73 + } 74 + 57 75 }
+51 -1
src/view/page/PhabricatorStandardPageView.php
··· 371 371 ' '); 372 372 } 373 373 374 + $notification_header = ''; 375 + $notification_dropdown = ''; 376 + 377 + if (PhabricatorEnv::getEnvConfig('notification.enabled') && 378 + $user->isLoggedIn()) { 379 + $aphlict_object_id = 'aphlictswfobject'; 380 + 381 + $aphlict_content = phutil_render_tag( 382 + 'object', 383 + array( 384 + 'classid' => 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000', 385 + ), 386 + '<param name="movie" value="/rsrc/swf/aphlict.swf" />'. 387 + '<param name="allowScriptAccess" value="always" />'. 388 + '<param name="wmode" value="opaque" />'. 389 + '<embed src="/rsrc/swf/aphlict.swf" wmode="opaque" id="'. 390 + $aphlict_object_id.'"></embed>'); 391 + 392 + Javelin::initBehavior('aphlict-dropdown', array()); 393 + 394 + 395 + $notification_indicator = 396 + javelin_render_tag( 397 + 'td', 398 + array( 399 + 'sigil' => 'aphlict-indicator', 400 + 'id' => 'phabricator-notification-indicator', 401 + ), 402 + id(new PhabricatorFeedStoryNotification) 403 + ->countUnread($user)); 404 + 405 + $notification_header = 406 + $notification_indicator. 407 + '<td>'. 408 + '<div style="height:1px; width:1px;">'. 409 + $aphlict_content. 410 + '</div>'. 411 + '</td>'; 412 + $notification_dropdown = 413 + javelin_render_tag( 414 + 'div', 415 + array( 416 + 'sigil' => 'aphlict-dropdown', 417 + 'id' => 'phabricator-notification-dropdown', 418 + ), 419 + ''); 420 + } 421 + 374 422 $header_chrome = null; 375 423 $footer_chrome = null; 376 424 if ($this->getShowChrome()) { ··· 400 448 '<td class="phabricator-login-details">'. 401 449 $login_stuff. 402 450 '</td>'. 451 + $notification_header. 403 452 '</tr>'. 404 - '</table>'; 453 + '</table>'. 454 + $notification_dropdown; 405 455 $footer_chrome = 406 456 '<div class="phabricator-page-foot">'. 407 457 $foot_links.
+51
webroot/rsrc/css/application/base/standard-page-view.css
··· 238 238 cursor: pointer; 239 239 240 240 } 241 + 242 + #phabricator-notification-indicator { 243 + background-color: #0069a6; 244 + text-align: center; 245 + font-size: 20px; 246 + vertical-align: middle; 247 + height: 40px; 248 + width: 40px; 249 + 250 + -moz-user-select: -moz-none; 251 + -khtml-user-select: none; 252 + -webkit-user-select: none; 253 + -o-user-select: none; 254 + } 255 + 256 + #phabricator-notification-indicator:hover { 257 + cursor: pointer; 258 + background-color: #0089d9; 259 + } 260 + 261 + #phabricator-notification-dropdown { 262 + 263 + word-wrap: break-word; 264 + 265 + overflow-y: auto; 266 + position: absolute; 267 + width: 600px; 268 + height: 300px; 269 + right: 0px; 270 + 271 + 272 + background-color: #f0f0f0; 273 + border: 1px solid darkgrey; 274 + box-shadow: 3px 3px #ccc; 275 + -webkit-box-shadow: 3px 3px #ccc; 276 + -moz-box-shadow: 3px 3px #ccc; 277 + 278 + z-index: 3; 279 + } 280 + 281 + .phabricator-notification-story-head { 282 + border-bottom: 1px solid darkgray; 283 + padding-top: 2px; 284 + padding-bottom: 2px; 285 + } 286 + 287 + 288 + .phabricator-notification-frame { 289 + padding-left: 5px; 290 + padding-right: 10px; 291 + }
+54
webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js
··· 1 + /** 2 + * @provides javelin-behavior-aphlict-dropdown 3 + * @requires javelin-behavior 4 + * javelin-aphlict 5 + * javelin-util 6 + * javelin-request 7 + * javelin-stratcom 8 + */ 9 + 10 + JX.behavior('aphlict-dropdown', function(config) { 11 + var dropdown = JX.$('phabricator-notification-dropdown'); 12 + var indicator = JX.$('phabricator-notification-indicator'); 13 + var visible = false; 14 + 15 + 16 + JX.DOM.hide(dropdown); 17 + 18 + //populate panel 19 + (new JX.Request('/notification/panel/', 20 + function(response) { 21 + JX.DOM.setContent(dropdown, JX.$H(response.content)); 22 + })).send(); 23 + 24 + 25 + JX.Stratcom.listen( 26 + 'click', 27 + null, 28 + function(e) { 29 + if(e.getNode('aphlict-dropdown') || 30 + e.getNode('aphlict-indicator')) { 31 + // Click is inside the dropdown, or on indicator 32 + return; 33 + } 34 + 35 + JX.DOM.hide(dropdown); 36 + visible = false; 37 + }); 38 + 39 + 40 + JX.DOM.listen( 41 + indicator, 42 + 'click', 43 + null, 44 + function(e) { 45 + if(visible) { 46 + JX.DOM.hide(dropdown); 47 + } else { 48 + JX.DOM.show(dropdown); 49 + } 50 + visible = !visible; 51 + } 52 + ) 53 + 54 + });