1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-09-19 16:58:48 +02:00

Show Aphlict connection status in notification menu

Summary:
Fixes T5373. Ref T5281. Several changes:

  - The `marshallExceptions` thing is useful if JS throws an exception when invoked from Flash, so set it. The resulting exceptions are a little odd (not escaped correctly, e.g.) but way better than nothing.
  - Put connection status in the notification menu.
  - When the connection fails, try to provide contextual help where we can.

Test Plan: {F169493}

Reviewers: chad, joshuaspence

Reviewed By: joshuaspence

Subscribers: epriestley

Maniphest Tasks: T5281, T5373

Differential Revision: https://secure.phabricator.com/D9700
This commit is contained in:
epriestley 2014-06-23 16:26:16 -07:00
parent 5dffd88737
commit 76cefde0b3
12 changed files with 217 additions and 40 deletions

View file

@ -7,8 +7,8 @@
return array(
'names' =>
array(
'core.pkg.css' => '22e4fc33',
'core.pkg.js' => 'f5ba2408',
'core.pkg.css' => 'f9c94804',
'core.pkg.js' => '8c184823',
'darkconsole.pkg.js' => 'df001cab',
'differential.pkg.css' => '4a93db37',
'differential.pkg.js' => 'd1443567',
@ -37,7 +37,7 @@ return array(
'rsrc/css/aphront/typeahead.css' => 'a989b5b3',
'rsrc/css/application/auth/auth.css' => '1e655982',
'rsrc/css/application/base/main-menu-view.css' => 'aceca0e9',
'rsrc/css/application/base/notification-menu.css' => 'cbff1b94',
'rsrc/css/application/base/notification-menu.css' => '8ae4a008',
'rsrc/css/application/base/phabricator-application-launch-view.css' => '8b7e271d',
'rsrc/css/application/base/standard-page-view.css' => '517cdfb1',
'rsrc/css/application/chatlog/chatlog.css' => '852140ff',
@ -346,9 +346,10 @@ return array(
'rsrc/image/texture/table_header.png' => '5c433037',
'rsrc/image/texture/table_header_hover.png' => '038ec3b9',
'rsrc/image/texture/table_header_tall.png' => 'd56b434f',
'rsrc/js/application/aphlict/Aphlict.js' => 'da12704d',
'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => '862ea0fe',
'rsrc/js/application/aphlict/Aphlict.js' => '4a07e8e3',
'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => 'f51afce0',
'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'a826c925',
'rsrc/js/application/aphlict/behavior-aphlict-status.js' => '58f7803f',
'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18',
'rsrc/js/application/config/behavior-reorder-fields.js' => '14a827de',
'rsrc/js/application/conpherence/behavior-menu.js' => 'f0a41b9f',
@ -490,7 +491,7 @@ return array(
'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
'rsrc/js/phuix/PHUIXActionView.js' => '6e8cefa4',
'rsrc/js/phuix/PHUIXDropdownMenu.js' => 'bd4c8dca',
'rsrc/swf/aphlict.swf' => 'ef64606d',
'rsrc/swf/aphlict.swf' => 'e5a24c72',
),
'symbols' =>
array(
@ -539,10 +540,11 @@ return array(
'herald-rule-editor' => '6c9e6fb8',
'herald-test-css' => '778b008e',
'inline-comment-summary-css' => '8cfd34e8',
'javelin-aphlict' => 'da12704d',
'javelin-aphlict' => '4a07e8e3',
'javelin-behavior' => '8a3ed18b',
'javelin-behavior-aphlict-dropdown' => '862ea0fe',
'javelin-behavior-aphlict-dropdown' => 'f51afce0',
'javelin-behavior-aphlict-listen' => 'a826c925',
'javelin-behavior-aphlict-status' => '58f7803f',
'javelin-behavior-aphront-basic-tokenizer' => 'b3a4b884',
'javelin-behavior-aphront-crop' => 'fa0f4fc2',
'javelin-behavior-aphront-drag-and-drop-textarea' => '92eb531d',
@ -725,7 +727,7 @@ return array(
'phabricator-nav-view-css' => '9283c2df',
'phabricator-notification' => '0c6946e7',
'phabricator-notification-css' => 'ef2c9b34',
'phabricator-notification-menu-css' => 'cbff1b94',
'phabricator-notification-menu-css' => '8ae4a008',
'phabricator-object-selector-css' => '029a133d',
'phabricator-phtize' => 'd254d646',
'phabricator-prefab' => '41ed7994',
@ -1190,6 +1192,11 @@ return array(
1 => 'javelin-dom',
2 => 'javelin-reactor-dom',
),
'4a07e8e3' =>
array(
0 => 'javelin-install',
1 => 'javelin-util',
),
'4d94d9c3' =>
array(
0 => 'javelin-behavior',
@ -1235,6 +1242,13 @@ return array(
2 => 'javelin-vector',
3 => 'javelin-dom',
),
'58f7803f' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-aphlict',
2 => 'phabricator-phtize',
3 => 'javelin-dom',
),
'59b251eb' =>
array(
0 => 'javelin-behavior',
@ -1477,16 +1491,6 @@ return array(
3 => 'javelin-workflow',
4 => 'javelin-stratcom',
),
'862ea0fe' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-request',
2 => 'javelin-stratcom',
3 => 'javelin-vector',
4 => 'javelin-dom',
5 => 'javelin-uri',
6 => 'javelin-behavior-device',
),
'880fa5ac' =>
array(
0 => 'javelin-behavior',
@ -1921,11 +1925,6 @@ return array(
1 => 'javelin-util',
2 => 'javelin-stratcom',
),
'da12704d' =>
array(
0 => 'javelin-install',
1 => 'javelin-util',
),
'dd7e8ef5' =>
array(
0 => 'javelin-behavior',
@ -2038,6 +2037,16 @@ return array(
5 => 'phuix-action-view',
6 => 'javelin-workflow',
),
'f51afce0' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-request',
2 => 'javelin-stratcom',
3 => 'javelin-vector',
4 => 'javelin-dom',
5 => 'javelin-uri',
6 => 'javelin-behavior-device',
),
'f588412e' =>
array(
0 => 'javelin-behavior',

View file

@ -1803,6 +1803,7 @@ phutil_register_library_map(array(
'PhabricatorNotificationPanelController' => 'applications/notification/controller/PhabricatorNotificationPanelController.php',
'PhabricatorNotificationQuery' => 'applications/notification/PhabricatorNotificationQuery.php',
'PhabricatorNotificationStatusController' => 'applications/notification/controller/PhabricatorNotificationStatusController.php',
'PhabricatorNotificationStatusView' => 'applications/notification/view/PhabricatorNotificationStatusView.php',
'PhabricatorNotificationTestController' => 'applications/notification/controller/PhabricatorNotificationTestController.php',
'PhabricatorOAuthClientAuthorization' => 'applications/oauthserver/storage/PhabricatorOAuthClientAuthorization.php',
'PhabricatorOAuthClientAuthorizationQuery' => 'applications/oauthserver/query/PhabricatorOAuthClientAuthorizationQuery.php',
@ -4631,6 +4632,7 @@ phutil_register_library_map(array(
'PhabricatorNotificationPanelController' => 'PhabricatorNotificationController',
'PhabricatorNotificationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorNotificationStatusController' => 'PhabricatorNotificationController',
'PhabricatorNotificationStatusView' => 'AphrontTagView',
'PhabricatorNotificationTestController' => 'PhabricatorNotificationController',
'PhabricatorOAuthClientAuthorization' =>
array(

View file

@ -25,16 +25,31 @@ final class PhabricatorNotificationPanelController
pht('You have no notifications.'));
}
$notifications_link = phutil_tag(
'a',
array(
'href' => '/notification/',
),
pht('Notifications'));
$connection_status = new PhabricatorNotificationStatusView();
$header = phutil_tag(
'div',
array(
'class' => 'phabricator-notification-header',
),
array(
$connection_status,
$notifications_link,
));
$content = hsprintf(
'<div class="phabricator-notification-header">%s %s</div>'.
'%s'.
'<div class="phabricator-notification-view-all">%s</div>',
phutil_tag(
'a',
array(
'href' => '/notification/',
),
pht('Notifications')),
'%s'.
'<div class="phabricator-notification-view-all">%s %s %s</div>',
$header,
$content,
javelin_tag(
'a',
array(
@ -43,7 +58,7 @@ final class PhabricatorNotificationPanelController
'class' => 'phabricator-notification-clear-all'
),
pht('Mark All Read')),
$content,
" \xC2\xB7 ",
phutil_tag(
'a',
array(

View file

@ -0,0 +1,34 @@
<?php
final class PhabricatorNotificationStatusView extends AphrontTagView {
protected function getTagAttributes() {
if (!$this->getID()) {
$this->setID(celerity_generate_unique_node_id());
}
Javelin::initBehavior(
'aphlict-status',
array(
'nodeID' => $this->getID(),
'pht' => array(
'setup' => pht('Setting Up Client'),
'start' => pht('Starting Client'),
'ready' => pht('Ready to Connect'),
'connecting' => pht('Connecting...'),
'connected' => pht('Connected'),
'error' => pht('Connection Error'),
'client' => pht('Connected Locally'),
'error.flash.xdomain' => pht(
'Unable to connect to Flash Policy Server. Check that the '.
'notification server is running and port 843 is not firewalled.'),
),
));
return array(
'class' => 'aphlict-connection-status',
);
}
}

View file

@ -42,10 +42,6 @@ package {
this.externalInvoke('log', message);
}
final protected function setStatus(status:String):void {
this.externalInvoke('status', {type: status});
}
}
}

View file

@ -41,6 +41,7 @@ package {
UncaughtErrorEvent.UNCAUGHT_ERROR,
this.uncaughtErrorHandler);
ExternalInterface.marshallExceptions = true;
ExternalInterface.addCallback('connect', this.externalConnect);
this.setStatus('ready');
@ -150,6 +151,10 @@ package {
this.externalInvoke('receive', msg);
}
public function setStatus(status:String, code:String = null):void {
this.externalInvoke('status', {type: status, code: code});
}
}
}

View file

@ -48,6 +48,9 @@ package {
private var socket:Socket;
private var readBuffer:ByteArray;
private var status:String;
private var statusCode:String;
public function AphlictMaster(server:String, port:Number) {
super();
@ -75,6 +78,8 @@ package {
if (!this.clients[client]) {
this.log('Registering client: ' + client);
this.clients[client] = new Date().getTime();
this.send.send(client, 'setStatus', this.status, this.statusCode);
}
}
@ -106,6 +111,8 @@ package {
}
private function connectToServer():void {
this.setStatusOnClients('connecting');
var socket:Socket = new Socket();
socket.addEventListener(Event.CONNECT, didConnectSocket);
@ -124,7 +131,7 @@ package {
}
private function didConnectSocket(event:Event):void {
this.externalInvoke('connected');
this.setStatusOnClients('connected');
// Send subscriptions
var phids = new Array();
@ -146,7 +153,15 @@ package {
}
private function didSecurityErrorSocket(event:SecurityErrorEvent):void {
this.externalInvoke('error', event.text);
var text = event.text;
// This is really gross but there doesn't seem to be anything else
// on the object which gives us an error code.
if (text.match(/^Error #2048/)) {
this.setStatusOnClients('error', 'error.flash.xdomain');
}
this.error(text);
}
public function subscribe(client:String, phids:Array):void {
@ -280,6 +295,18 @@ package {
}
}
private function setStatusOnClients(
status:String,
code:String = null):void {
this.status = status;
this.statusCode = code;
for (var client:String in this.clients) {
this.send.send(client, 'setStatus', status, code);
}
}
}
}

View file

@ -97,3 +97,17 @@
padding: 8px;
font-size: 12px;
}
.phabricator-notification-menu .aphlict-connection-status {
float: right;
font-weight: normal;
color: {$lightgreytext};
}
.aphlict-connection-status .aphlict-connection-status-connected {
color: {$green};
}
.aphlict-connection-status .aphlict-connection-status-error {
color: {$red};
}

View file

@ -28,7 +28,7 @@ JX.install('Aphlict', {
construct: function(id, server, port, subscriptions) {
if (__DEV__) {
if (JX.Aphlict._instance) {
JX.$E('Aphlict object is a singleton!');
JX.$E('Aphlict object is a singleton.');
}
}
@ -36,17 +36,24 @@ JX.install('Aphlict', {
this._server = server;
this._port = port;
this._subscriptions = subscriptions;
this._setStatus('setup');
JX.Aphlict._instance = this;
},
events: ['didChangeStatus'],
members: {
_id: null,
_server: null,
_port: null,
_subscriptions: null,
_status: null,
_statusCode: null,
start: function(node, uri) {
this._setStatus('start');
// NOTE: This is grotesque, but seems to work everywhere.
node.innerHTML =
'<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000">' +
@ -72,6 +79,20 @@ JX.install('Aphlict', {
this._server,
this._port,
this._subscriptions);
},
getStatus: function() {
return this._status;
},
getStatusCode: function() {
return this._statusCode;
},
_setStatus: function(status, code) {
this._status = status;
this._statusCode = code || null;
this.invoke('didChangeStatus');
}
},
@ -98,6 +119,7 @@ JX.install('Aphlict', {
}
if (type == 'status') {
client._setStatus(message.type, message.code);
switch (message.type) {
case 'ready':
client._didStartFlash();

View file

@ -73,6 +73,12 @@ JX.behavior('aphlict-dropdown', function(config, statics) {
return;
}
if (!e.getNode('notification')) {
// User clicked somewhere in the dead area of the menu, like the header
// or footer.
return;
}
// If the user clicked a notification (but missed a link) and it has a
// primary URI, go there.
var href = e.getNodeData('notification').href;

View file

@ -0,0 +1,47 @@
/**
* @provides javelin-behavior-aphlict-status
* @requires javelin-behavior
* javelin-aphlict
* phabricator-phtize
* javelin-dom
* @javelin
*/
JX.behavior('aphlict-status', function(config) {
var pht = JX.phtize(config.pht);
function update() {
var client = JX.Aphlict.getInstance();
if (!client) {
return;
}
var node;
try {
node = JX.$(config.nodeID);
} catch (ignored) {
return;
}
var tip = null;
var status = client.getStatus();
if (status == 'error') {
tip = pht(client.getStatusCode());
}
var status_node = JX.$N(
'span',
{
className: 'aphlict-connection-status-' + status,
sigil: tip ? 'has-tooltip' : null,
meta: tip ? {tip: tip, align: 'S', size: 300} : {}
},
pht(status));
JX.DOM.setContent(node, status_node);
}
JX.Aphlict.listen('didChangeStatus', update);
update();
});

Binary file not shown.