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

Fix several duplication/replay behaviors in Aphlict

Summary:
Ref T12566. Ref T12563. This fixes three bugs with Aphlict replay stuff:

First, Conphernece would try to repaint the UI even if no thread was open. Only repaint when a thread is open.

Second, although we deduplicate JX.Leader messages, we didn't deduplicate actual notification messages. If you browsed the leader window, then it re-elected itelf as a leader and replayed history, it could rebroadcast notifications and other windows could show doubles. Deduplicate notifications to prevent this.

Third, we always replayed the last 60 seconds of history. When you browsed the leader window, whichever window became the new leader (possibly the one you just browsed) could replay messages from before it had opened, leading to duplicate messages. Particularly, after receiving a message and then browsing you could see that message again. Instead, only replay history as far back as when the window first opened.

Test Plan:
- Clicked "Repaint" with a thread open, saw a repaint. Clicked "Repaint" with Conpherence open but no thread, no repaint and no 404 request to `/update/null/`.
- In browser A, opened three windows. In browser B, sent a notification. In browser A, browsed the leader window away twice in a row. Observed that the window which never became a leader doesn't duplicate notifications.
- In browser A, opened three windows. In browser B, sent a notification. In browser A, browsed the leader window away over and over again. Observed that replay requests issued with appropriate history windows.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T12566, T12563

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

+67 -44
+39 -39
resources/celerity/map.php
··· 10 10 'conpherence.pkg.css' => 'a34d59bd', 11 11 'conpherence.pkg.js' => '5f86c17d', 12 12 'core.pkg.css' => '959330a2', 13 - 'core.pkg.js' => '5363ae35', 13 + 'core.pkg.js' => '47a69358', 14 14 'darkconsole.pkg.js' => '1f9a31bc', 15 15 'differential.pkg.css' => '90b30783', 16 16 'differential.pkg.js' => 'ddfeb49b', ··· 362 362 'rsrc/image/texture/table_header.png' => '5c433037', 363 363 'rsrc/image/texture/table_header_hover.png' => '038ec3b9', 364 364 'rsrc/image/texture/table_header_tall.png' => 'd56b434f', 365 - 'rsrc/js/application/aphlict/Aphlict.js' => '674e335f', 365 + 'rsrc/js/application/aphlict/Aphlict.js' => 'e1d4b11a', 366 366 'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => 'caade6f2', 367 - 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => '06e7f30e', 367 + 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => '3c547a81', 368 368 'rsrc/js/application/aphlict/behavior-aphlict-status.js' => '5e2634b9', 369 369 'rsrc/js/application/aphlict/behavior-desktop-notifications-control.js' => 'd5a2d665', 370 370 'rsrc/js/application/calendar/behavior-day-view.js' => '4b3c4443', 371 371 'rsrc/js/application/calendar/behavior-event-all-day.js' => 'b41537c9', 372 372 'rsrc/js/application/calendar/behavior-month-view.js' => 'fe33e256', 373 373 'rsrc/js/application/config/behavior-reorder-fields.js' => 'b6993408', 374 - 'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '311eae46', 374 + 'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '4d863052', 375 375 'rsrc/js/application/conpherence/behavior-conpherence-search.js' => '9bbf3762', 376 376 'rsrc/js/application/conpherence/behavior-durable-column.js' => 'aa3bd034', 377 377 'rsrc/js/application/conpherence/behavior-menu.js' => '80dda04a', ··· 561 561 'conpherence-message-pane-css' => '14199428', 562 562 'conpherence-notification-css' => 'cef0a3fc', 563 563 'conpherence-participant-pane-css' => '26a3ce56', 564 - 'conpherence-thread-manager' => '311eae46', 564 + 'conpherence-thread-manager' => '4d863052', 565 565 'conpherence-transaction-css' => '85129c68', 566 566 'd3' => 'a11a5ff2', 567 567 'differential-changeset-view-css' => '41af6d25', ··· 584 584 'herald-rule-editor' => 'd6a7e717', 585 585 'herald-test-css' => 'a52e323e', 586 586 'inline-comment-summary-css' => '51efda3a', 587 - 'javelin-aphlict' => '674e335f', 587 + 'javelin-aphlict' => 'e1d4b11a', 588 588 'javelin-behavior' => '61cbc29a', 589 589 'javelin-behavior-aphlict-dropdown' => 'caade6f2', 590 - 'javelin-behavior-aphlict-listen' => '06e7f30e', 590 + 'javelin-behavior-aphlict-listen' => '3c547a81', 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', ··· 948 948 'javelin-stratcom', 949 949 'javelin-workflow', 950 950 ), 951 - '06e7f30e' => array( 952 - 'javelin-behavior', 953 - 'javelin-aphlict', 954 - 'javelin-stratcom', 955 - 'javelin-request', 956 - 'javelin-uri', 957 - 'javelin-dom', 958 - 'javelin-json', 959 - 'javelin-router', 960 - 'javelin-util', 961 - 'javelin-leader', 962 - 'javelin-sound', 963 - 'phabricator-notification', 964 - ), 965 951 '0825c27a' => array( 966 952 'javelin-behavior', 967 953 'javelin-dom', ··· 1132 1118 ), 1133 1119 '2ee659ce' => array( 1134 1120 'javelin-install', 1135 - ), 1136 - '311eae46' => array( 1137 - 'javelin-dom', 1138 - 'javelin-util', 1139 - 'javelin-stratcom', 1140 - 'javelin-install', 1141 - 'javelin-aphlict', 1142 - 'javelin-workflow', 1143 - 'javelin-router', 1144 - 'javelin-behavior-device', 1145 - 'javelin-vector', 1146 1121 ), 1147 1122 '31420f77' => array( 1148 1123 'javelin-behavior', ··· 1166 1141 'javelin-dom', 1167 1142 'javelin-magical-init', 1168 1143 ), 1144 + '3c547a81' => array( 1145 + 'javelin-behavior', 1146 + 'javelin-aphlict', 1147 + 'javelin-stratcom', 1148 + 'javelin-request', 1149 + 'javelin-uri', 1150 + 'javelin-dom', 1151 + 'javelin-json', 1152 + 'javelin-router', 1153 + 'javelin-util', 1154 + 'javelin-leader', 1155 + 'javelin-sound', 1156 + 'phabricator-notification', 1157 + ), 1169 1158 '3cb0b2fc' => array( 1170 1159 'javelin-behavior', 1171 1160 'javelin-dom', ··· 1284 1273 'javelin-uri', 1285 1274 'phabricator-notification', 1286 1275 ), 1276 + '4d863052' => array( 1277 + 'javelin-dom', 1278 + 'javelin-util', 1279 + 'javelin-stratcom', 1280 + 'javelin-install', 1281 + 'javelin-aphlict', 1282 + 'javelin-workflow', 1283 + 'javelin-router', 1284 + 'javelin-behavior-device', 1285 + 'javelin-vector', 1286 + ), 1287 1287 '4e3e79a6' => array( 1288 1288 'javelin-behavior', 1289 1289 'javelin-stratcom', ··· 1408 1408 'javelin-stratcom', 1409 1409 'javelin-workflow', 1410 1410 'javelin-dom', 1411 - ), 1412 - '674e335f' => array( 1413 - 'javelin-install', 1414 - 'javelin-util', 1415 - 'javelin-websocket', 1416 - 'javelin-leader', 1417 - 'javelin-json', 1418 1411 ), 1419 1412 '680ea2c8' => array( 1420 1413 'javelin-install', ··· 2126 2119 'javelin-workflow', 2127 2120 'javelin-dom', 2128 2121 'phabricator-draggable-list', 2122 + ), 2123 + 'e1d4b11a' => array( 2124 + 'javelin-install', 2125 + 'javelin-util', 2126 + 'javelin-websocket', 2127 + 'javelin-leader', 2128 + 'javelin-json', 2129 2129 ), 2130 2130 'e1ff79b1' => array( 2131 2131 'javelin-behavior',
+1
src/applications/notification/controller/PhabricatorNotificationIndividualController.php
··· 47 47 'title' => $data['title'], 48 48 'body' => $data['body'], 49 49 'content' => hsprintf('%s', $content), 50 + 'uniqueID' => 'story/'.$story->getChronologicalKey(), 50 51 ); 51 52 52 53 return id(new AphrontAjaxResponse())->setContent($response);
+17 -1
webroot/rsrc/js/application/aphlict/Aphlict.js
··· 29 29 this._uri = uri; 30 30 this._subscriptions = subscriptions; 31 31 this._setStatus('setup'); 32 + this._startTime = new Date().getTime(); 32 33 33 34 JX.Aphlict._instance = this; 34 35 }, ··· 42 43 _status: null, 43 44 _isReconnect: false, 44 45 _keepaliveInterval: false, 46 + _startTime: null, 45 47 46 48 start: function() { 47 49 JX.Leader.listen('onBecomeLeader', JX.bind(this, this._lead)); ··· 121 123 }, 122 124 123 125 replay: function() { 126 + var age = 60000; 127 + 128 + // If the page was loaded a few moments ago, only query for recent 129 + // history. This keeps us from replaying events over and over again as 130 + // a user browses normally. 131 + 132 + // Allow a small margin of error for the actual page load time. It's 133 + // also fine to replay a notification which the user saw for a brief 134 + // moment on the previous page. 135 + var extra_time = 500; 136 + var now = new Date().getTime(); 137 + 138 + age = Math.min(extra_time + (now - this._startTime), age); 139 + 124 140 var replay = { 125 - age: 60000 141 + age: age 126 142 }; 127 143 128 144 JX.Leader.broadcast(null, {type: 'aphlict.replay', data: replay});
+6 -4
webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js
··· 66 66 return; 67 67 } 68 68 69 - JX.Leader.broadcast(null, { 70 - type: 'notification.individual', 71 - data: response 72 - }); 69 + JX.Leader.broadcast( 70 + response.uniqueID, 71 + { 72 + type: 'notification.individual', 73 + data: response 74 + }); 73 75 } 74 76 75 77 JX.Stratcom.listen('aphlict-notification-message', null, function(e) {
+4
webroot/rsrc/js/application/conpherence/ConpherenceThreadManager.js
··· 245 245 'aphlict-reconnect', 246 246 null, 247 247 JX.bind(this, function() { 248 + if (!this._loadedThreadPHID) { 249 + return; 250 + } 251 + 248 252 this._updateThread(); 249 253 })); 250 254