@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.

Allow more granularity on real-time notifications

Summary: Fixes T12792. Expands the Notifications to "web, desktop, both, or none" for real-time notifications in settings.

Test Plan: Test with "test notifications" button, and while logged into two accounts with each of the 4 settings.

Reviewers: epriestley

Reviewed By: epriestley

Spies: Korvin

Maniphest Tasks: T12792

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

+140 -79
+35 -35
resources/celerity/map.php
··· 10 10 'conpherence.pkg.css' => 'e68cf1fa', 11 11 'conpherence.pkg.js' => 'b5b51108', 12 12 'core.pkg.css' => 'fe4effd6', 13 - 'core.pkg.js' => '5d80e0db', 13 + 'core.pkg.js' => '396dee49', 14 14 'darkconsole.pkg.js' => '1f9a31bc', 15 15 'differential.pkg.css' => '45951e9e', 16 16 'differential.pkg.js' => 'b71b8c5d', ··· 375 375 'rsrc/image/texture/table_header_tall.png' => 'd56b434f', 376 376 'rsrc/js/application/aphlict/Aphlict.js' => 'e1d4b11a', 377 377 'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => 'caade6f2', 378 - 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => '3c547a81', 378 + 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'a14cbdfc', 379 379 'rsrc/js/application/aphlict/behavior-aphlict-status.js' => '5e2634b9', 380 - 'rsrc/js/application/aphlict/behavior-desktop-notifications-control.js' => 'd5a2d665', 380 + 'rsrc/js/application/aphlict/behavior-desktop-notifications-control.js' => '27ca6289', 381 381 'rsrc/js/application/calendar/behavior-day-view.js' => '4b3c4443', 382 382 'rsrc/js/application/calendar/behavior-event-all-day.js' => 'b41537c9', 383 383 'rsrc/js/application/calendar/behavior-month-view.js' => 'fe33e256', ··· 468 468 'rsrc/js/core/KeyboardShortcut.js' => '1ae869f2', 469 469 'rsrc/js/core/KeyboardShortcutManager.js' => 'c19dd9b9', 470 470 'rsrc/js/core/MultirowRowManager.js' => 'b5d57730', 471 - 'rsrc/js/core/Notification.js' => 'ccf1cbf8', 471 + 'rsrc/js/core/Notification.js' => '5c3349b2', 472 472 'rsrc/js/core/Prefab.js' => 'c5af80a2', 473 473 'rsrc/js/core/ShapedRequest.js' => '7cbe244b', 474 474 'rsrc/js/core/TextAreaUtils.js' => '320810c8', ··· 587 587 'javelin-aphlict' => 'e1d4b11a', 588 588 'javelin-behavior' => '61cbc29a', 589 589 'javelin-behavior-aphlict-dropdown' => 'caade6f2', 590 - 'javelin-behavior-aphlict-listen' => '3c547a81', 590 + 'javelin-behavior-aphlict-listen' => 'a14cbdfc', 591 591 'javelin-behavior-aphlict-status' => '5e2634b9', 592 592 'javelin-behavior-aphront-basic-tokenizer' => 'b3a4b884', 593 593 'javelin-behavior-aphront-drag-and-drop-textarea' => '484a6e22', ··· 612 612 'javelin-behavior-dashboard-query-panel-select' => '453c5375', 613 613 'javelin-behavior-dashboard-tab-panel' => 'd4eecc63', 614 614 'javelin-behavior-day-view' => '4b3c4443', 615 - 'javelin-behavior-desktop-notifications-control' => 'd5a2d665', 615 + 'javelin-behavior-desktop-notifications-control' => '27ca6289', 616 616 'javelin-behavior-detect-timezone' => '4c193c96', 617 617 'javelin-behavior-device' => 'bb1dd507', 618 618 'javelin-behavior-diff-preview-link' => '051c7832', ··· 791 791 'phabricator-keyboard-shortcut-manager' => 'c19dd9b9', 792 792 'phabricator-main-menu-view' => '16053029', 793 793 'phabricator-nav-view-css' => 'faf6a6fc', 794 - 'phabricator-notification' => 'ccf1cbf8', 794 + 'phabricator-notification' => '5c3349b2', 795 795 'phabricator-notification-css' => '3f6c89c9', 796 796 'phabricator-notification-menu-css' => '73fefdfa', 797 797 'phabricator-object-selector-css' => '85ee8ce6', ··· 1058 1058 'phabricator-drag-and-drop-file-upload', 1059 1059 'javelin-workboard-board', 1060 1060 ), 1061 + '27ca6289' => array( 1062 + 'javelin-behavior', 1063 + 'javelin-stratcom', 1064 + 'javelin-dom', 1065 + 'javelin-uri', 1066 + 'phabricator-notification', 1067 + ), 1061 1068 '2926fff2' => array( 1062 1069 'javelin-behavior', 1063 1070 'javelin-dom', ··· 1114 1121 'javelin-vector', 1115 1122 'javelin-dom', 1116 1123 'javelin-magical-init', 1117 - ), 1118 - '3c547a81' => array( 1119 - 'javelin-behavior', 1120 - 'javelin-aphlict', 1121 - 'javelin-stratcom', 1122 - 'javelin-request', 1123 - 'javelin-uri', 1124 - 'javelin-dom', 1125 - 'javelin-json', 1126 - 'javelin-router', 1127 - 'javelin-util', 1128 - 'javelin-leader', 1129 - 'javelin-sound', 1130 - 'phabricator-notification', 1131 1124 ), 1132 1125 '3cb0b2fc' => array( 1133 1126 'javelin-behavior', ··· 1338 1331 'javelin-vector', 1339 1332 'javelin-dom', 1340 1333 ), 1334 + '5c3349b2' => array( 1335 + 'javelin-install', 1336 + 'javelin-dom', 1337 + 'javelin-stratcom', 1338 + 'javelin-util', 1339 + 'phabricator-notification-css', 1340 + ), 1341 1341 '5c54cbf3' => array( 1342 1342 'javelin-behavior', 1343 1343 'javelin-stratcom', ··· 1676 1676 'javelin-util', 1677 1677 'phabricator-keyboard-shortcut', 1678 1678 ), 1679 + 'a14cbdfc' => array( 1680 + 'javelin-behavior', 1681 + 'javelin-aphlict', 1682 + 'javelin-stratcom', 1683 + 'javelin-request', 1684 + 'javelin-uri', 1685 + 'javelin-dom', 1686 + 'javelin-json', 1687 + 'javelin-router', 1688 + 'javelin-util', 1689 + 'javelin-leader', 1690 + 'javelin-sound', 1691 + 'phabricator-notification', 1692 + ), 1679 1693 'a37126bd' => array( 1680 1694 'javelin-install', 1681 1695 'javelin-dom', ··· 1951 1965 'cae95e89' => array( 1952 1966 'syntax-default-css', 1953 1967 ), 1954 - 'ccf1cbf8' => array( 1955 - 'javelin-install', 1956 - 'javelin-dom', 1957 - 'javelin-stratcom', 1958 - 'javelin-util', 1959 - 'phabricator-notification-css', 1960 - ), 1961 1968 'cd2b9b77' => array( 1962 1969 'phui-oi-list-view-css', 1963 1970 ), ··· 1995 2002 'javelin-behavior', 1996 2003 'javelin-dom', 1997 2004 'javelin-stratcom', 1998 - ), 1999 - 'd5a2d665' => array( 2000 - 'javelin-behavior', 2001 - 'javelin-stratcom', 2002 - 'javelin-dom', 2003 - 'javelin-uri', 2004 - 'phabricator-notification', 2005 2005 ), 2006 2006 'd6a7e717' => array( 2007 2007 'multirow-row-manager',
+4 -4
src/__phutil_library_map__.php
··· 2647 2647 'PhabricatorDebugController' => 'applications/system/controller/PhabricatorDebugController.php', 2648 2648 'PhabricatorDefaultRequestExceptionHandler' => 'aphront/handler/PhabricatorDefaultRequestExceptionHandler.php', 2649 2649 'PhabricatorDefaultSyntaxStyle' => 'infrastructure/syntax/PhabricatorDefaultSyntaxStyle.php', 2650 - 'PhabricatorDesktopNotificationsSetting' => 'applications/settings/setting/PhabricatorDesktopNotificationsSetting.php', 2651 - 'PhabricatorDesktopNotificationsSettingsPanel' => 'applications/settings/panel/PhabricatorDesktopNotificationsSettingsPanel.php', 2652 2650 'PhabricatorDestructibleCodex' => 'applications/system/codex/PhabricatorDestructibleCodex.php', 2653 2651 'PhabricatorDestructibleCodexInterface' => 'applications/system/interface/PhabricatorDestructibleCodexInterface.php', 2654 2652 'PhabricatorDestructibleInterface' => 'applications/system/interface/PhabricatorDestructibleInterface.php', ··· 3214 3212 'PhabricatorNotificationTestFeedStory' => 'applications/notification/feed/PhabricatorNotificationTestFeedStory.php', 3215 3213 'PhabricatorNotificationUIExample' => 'applications/uiexample/examples/PhabricatorNotificationUIExample.php', 3216 3214 'PhabricatorNotificationsApplication' => 'applications/notification/application/PhabricatorNotificationsApplication.php', 3215 + 'PhabricatorNotificationsSetting' => 'applications/settings/setting/PhabricatorNotificationsSetting.php', 3216 + 'PhabricatorNotificationsSettingsPanel' => 'applications/settings/panel/PhabricatorNotificationsSettingsPanel.php', 3217 3217 'PhabricatorNuanceApplication' => 'applications/nuance/application/PhabricatorNuanceApplication.php', 3218 3218 'PhabricatorOAuth1AuthProvider' => 'applications/auth/provider/PhabricatorOAuth1AuthProvider.php', 3219 3219 'PhabricatorOAuth1SecretTemporaryTokenType' => 'applications/auth/provider/PhabricatorOAuth1SecretTemporaryTokenType.php', ··· 7952 7952 'PhabricatorDebugController' => 'PhabricatorController', 7953 7953 'PhabricatorDefaultRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler', 7954 7954 'PhabricatorDefaultSyntaxStyle' => 'PhabricatorSyntaxStyle', 7955 - 'PhabricatorDesktopNotificationsSetting' => 'PhabricatorInternalSetting', 7956 - 'PhabricatorDesktopNotificationsSettingsPanel' => 'PhabricatorSettingsPanel', 7957 7955 'PhabricatorDestructibleCodex' => 'Phobject', 7958 7956 'PhabricatorDestructionEngine' => 'Phobject', 7959 7957 'PhabricatorDestructionEngineExtension' => 'Phobject', ··· 8577 8575 'PhabricatorNotificationTestFeedStory' => 'PhabricatorFeedStory', 8578 8576 'PhabricatorNotificationUIExample' => 'PhabricatorUIExample', 8579 8577 'PhabricatorNotificationsApplication' => 'PhabricatorApplication', 8578 + 'PhabricatorNotificationsSetting' => 'PhabricatorInternalSetting', 8579 + 'PhabricatorNotificationsSettingsPanel' => 'PhabricatorSettingsPanel', 8580 8580 'PhabricatorNuanceApplication' => 'PhabricatorApplication', 8581 8581 'PhabricatorOAuth1AuthProvider' => 'PhabricatorOAuthAuthProvider', 8582 8582 'PhabricatorOAuth1SecretTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
+9 -4
src/applications/notification/builder/PhabricatorNotificationBuilder.php
··· 145 145 $dict = array(); 146 146 147 147 $viewer = $this->user; 148 - $desktop_key = PhabricatorDesktopNotificationsSetting::SETTINGKEY; 149 - $desktop_enabled = $viewer->getUserSetting($desktop_key); 148 + $key = PhabricatorNotificationsSetting::SETTINGKEY; 149 + $setting = $viewer->getUserSetting($key); 150 + $desktop_ready = PhabricatorNotificationsSetting::desktopReady($setting); 151 + $web_ready = PhabricatorNotificationsSetting::webReady($setting); 150 152 151 153 foreach ($stories as $story) { 152 154 if ($story instanceof PhabricatorApplicationTransactionFeedStory) { 153 155 $dict[] = array( 154 - 'desktopReady' => $desktop_enabled, 156 + 'desktopReady' => $desktop_ready, 157 + 'webReady' => $web_ready, 155 158 'title' => $story->renderText(), 156 159 'body' => $story->renderTextBody(), 157 160 'href' => $story->getURI(), ··· 159 162 ); 160 163 } else if ($story instanceof PhabricatorNotificationTestFeedStory) { 161 164 $dict[] = array( 162 - 'desktopReady' => $desktop_enabled, 165 + 'desktopReady' => $desktop_ready, 166 + 'webReady' => $web_ready, 163 167 'title' => pht('Test Notification'), 164 168 'body' => $story->renderText(), 165 169 'href' => null, ··· 168 172 } else { 169 173 $dict[] = array( 170 174 'desktopReady' => false, 175 + 'webReady' => false, 171 176 'title' => null, 172 177 'body' => null, 173 178 'href' => null,
+1
src/applications/notification/controller/PhabricatorNotificationIndividualController.php
··· 42 42 'pertinent' => true, 43 43 'primaryObjectPHID' => $story->getPrimaryObjectPHID(), 44 44 'desktopReady' => $data['desktopReady'], 45 + 'webReady' => $data['webReady'], 45 46 'href' => $data['href'], 46 47 'icon' => $data['icon'], 47 48 'title' => $data['title'],
+28 -18
src/applications/settings/panel/PhabricatorDesktopNotificationsSettingsPanel.php src/applications/settings/panel/PhabricatorNotificationsSettingsPanel.php
··· 1 1 <?php 2 2 3 - final class PhabricatorDesktopNotificationsSettingsPanel 3 + final class PhabricatorNotificationsSettingsPanel 4 4 extends PhabricatorSettingsPanel { 5 5 6 6 public function isEnabled() { ··· 14 14 } 15 15 16 16 public function getPanelKey() { 17 - return 'desktopnotifications'; 17 + return 'notifications'; 18 18 } 19 19 20 20 public function getPanelName() { 21 - return pht('Desktop Notifications'); 21 + return pht('Notifications'); 22 22 } 23 23 24 24 public function getPanelGroupKey() { ··· 29 29 $viewer = $this->getViewer(); 30 30 $preferences = $this->getPreferences(); 31 31 32 - $notifications_key = PhabricatorDesktopNotificationsSetting::SETTINGKEY; 32 + $notifications_key = PhabricatorNotificationsSetting::SETTINGKEY; 33 33 $notifications_value = $preferences->getSettingValue($notifications_key); 34 34 35 35 if ($request->isFormPost()) { ··· 43 43 ->setURI($this->getPanelURI('?saved=true')); 44 44 } 45 45 46 - $title = pht('Desktop Notifications'); 46 + $title = pht('Notifications'); 47 47 $control_id = celerity_generate_unique_node_id(); 48 48 $status_id = celerity_generate_unique_node_id(); 49 49 $browser_status_id = celerity_generate_unique_node_id(); ··· 97 97 'id' => $message_id, 98 98 )); 99 99 100 + $saved_box = null; 101 + if ($request->getBool('saved')) { 102 + $saved_box = id(new PHUIInfoView()) 103 + ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) 104 + ->appendChild(pht('Changes saved.')); 105 + } 106 + 100 107 $status_box = id(new PHUIInfoView()) 101 108 ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) 102 109 ->setID($status_id) 103 110 ->setIsHidden(true) 104 111 ->appendChild($message_container); 105 112 113 + $status_box = id(new PHUIBoxView()) 114 + ->addClass('mll mlr') 115 + ->appendChild($status_box); 116 + 106 117 $control_config = array( 107 118 'controlID' => $control_id, 108 119 'statusID' => $status_id, 109 120 'messageID' => $message_id, 110 121 'browserStatusID' => $browser_status_id, 111 122 'defaultMode' => 0, 112 - 'desktopMode' => 1, 123 + 'desktop' => 1, 124 + 'desktopOnly' => 2, 113 125 'cancelAsk' => $cancel_ask, 114 126 'grantedAsk' => $accept_ask, 115 127 'deniedAsk' => $reject_ask, ··· 127 139 ->setControlID($control_id) 128 140 ->setName($notifications_key) 129 141 ->setValue($notifications_value) 130 - ->setOptions( 131 - array( 132 - 1 => pht('Send Desktop Notifications Too'), 133 - 0 => pht('Send Application Notifications Only'), 134 - )) 142 + ->setOptions(PhabricatorNotificationsSetting::getOptionsMap()) 135 143 ->setCaption( 136 144 pht( 137 - 'Should Phabricator send desktop notifications? These are sent '. 138 - 'in addition to the notifications within the Phabricator '. 139 - 'application.')) 145 + 'Phabricator can send real-time notifications to your web browser '. 146 + 'or to your desktop. Select where you\'d want to receive these '. 147 + 'real-time updates.')) 140 148 ->initBehavior( 141 149 'desktop-notifications-control', 142 150 $control_config)) ··· 154 162 $form_box = id(new PHUIObjectBoxView()) 155 163 ->setHeader( 156 164 id(new PHUIHeaderView()) 157 - ->setHeader(pht('Desktop Notifications')) 165 + ->setHeader(pht('Notifications')) 158 166 ->addActionLink($test_button)) 159 - ->setForm($form) 160 167 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 161 - ->setInfoView($status_box) 162 - ->setFormSaved($request->getBool('saved')); 168 + ->appendChild(array( 169 + $saved_box, 170 + $status_box, 171 + $form, 172 + )); 163 173 164 174 $browser_status_box = id(new PHUIInfoView()) 165 175 ->setID($browser_status_id)
-12
src/applications/settings/setting/PhabricatorDesktopNotificationsSetting.php
··· 1 - <?php 2 - 3 - final class PhabricatorDesktopNotificationsSetting 4 - extends PhabricatorInternalSetting { 5 - 6 - const SETTINGKEY = 'desktop-notifications'; 7 - 8 - public function getSettingName() { 9 - return pht('Desktop Notifications'); 10 - } 11 - 12 - }
+44
src/applications/settings/setting/PhabricatorNotificationsSetting.php
··· 1 + <?php 2 + 3 + final class PhabricatorNotificationsSetting 4 + extends PhabricatorInternalSetting { 5 + 6 + const SETTINGKEY = 'desktop-notifications'; 7 + 8 + const WEB_ONLY = 0; 9 + const WEB_AND_DESKTOP = 1; 10 + const DESKTOP_ONLY = 2; 11 + const NONE = 3; 12 + 13 + public function getSettingName() { 14 + return pht('Notifications'); 15 + } 16 + 17 + public static function getOptionsMap() { 18 + return array( 19 + self::WEB_ONLY => pht('Web Only'), 20 + self::WEB_AND_DESKTOP => pht('Web and Desktop'), 21 + self::DESKTOP_ONLY => pht('Desktop Only'), 22 + self::NONE => pht('No Notifications'), 23 + ); 24 + } 25 + 26 + public static function desktopReady($option) { 27 + switch ($option) { 28 + case self::WEB_AND_DESKTOP: 29 + case self::DESKTOP_ONLY: 30 + return true; 31 + } 32 + return false; 33 + } 34 + 35 + public static function webReady($option) { 36 + switch ($option) { 37 + case self::WEB_AND_DESKTOP: 38 + case self::WEB_ONLY: 39 + return true; 40 + } 41 + return false; 42 + } 43 + 44 + }
+1
webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js
··· 82 82 new JX.Notification() 83 83 .setContent(JX.$H(response.content)) 84 84 .setDesktopReady(response.desktopReady) 85 + .setWebReady(response.webReady) 85 86 .setKey(response.primaryObjectPHID) 86 87 .setTitle(response.title) 87 88 .setBody(response.body)
+6 -6
webroot/rsrc/js/application/aphlict/behavior-desktop-notifications-control.js
··· 84 84 return; 85 85 } 86 86 var value = e.getTarget().value; 87 - if (value == config.desktopMode) { 88 - window.Notification.requestPermission( 89 - function (permission) { 90 - updateFormStatus(permission); 91 - updateBrowserStatus(permission); 92 - }); 87 + if ((value == config.desktop) || (value == config.desktopOnly)) { 88 + window.Notification.requestPermission( 89 + function (permission) { 90 + updateFormStatus(permission); 91 + updateBrowserStatus(permission); 92 + }); 93 93 } else { 94 94 var statusEl = JX.$(config.statusID); 95 95 JX.DOM.hide(statusEl);
+12
webroot/rsrc/js/core/Notification.js
··· 27 27 _hideTimer : null, 28 28 _duration : 12000, 29 29 _desktopReady : false, 30 + _webReady : false, 30 31 _key : null, 31 32 _title : null, 32 33 _body : null, ··· 35 36 36 37 show : function() { 37 38 var self = JX.Notification; 39 + 40 + // This person doesn't like any real-time notification 41 + if (!this._desktopReady && !this._webReady) { 42 + return; 43 + } 44 + 38 45 if (!this._visible) { 39 46 this._visible = true; 40 47 ··· 89 96 90 97 setDesktopReady : function(ready) { 91 98 this._desktopReady = ready; 99 + return this; 100 + }, 101 + 102 + setWebReady : function(ready) { 103 + this._webReady = ready; 92 104 return this; 93 105 }, 94 106