diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -10,8 +10,8 @@ 'conpherence.pkg.css' => 'a34d59bd', 'conpherence.pkg.js' => '5f86c17d', 'core.pkg.css' => '959330a2', - 'core.pkg.js' => '941db947', - 'darkconsole.pkg.js' => '061371d8', + 'core.pkg.js' => 'd7ca5b9a', + 'darkconsole.pkg.js' => 'a2faee86', 'differential.pkg.css' => '90b30783', 'differential.pkg.js' => 'ddfeb49b', 'diffusion.pkg.css' => '91c5d3a6', @@ -20,7 +20,7 @@ 'maniphest.pkg.css' => '4845691a', 'maniphest.pkg.js' => '5ab2753f', 'rsrc/css/aphront/aphront-bars.css' => '231ac33c', - 'rsrc/css/aphront/dark-console.css' => '07dd8d38', + 'rsrc/css/aphront/dark-console.css' => 'e7c6e44d', 'rsrc/css/aphront/dialog-view.css' => '685c7e2d', 'rsrc/css/aphront/list-filter-view.css' => '5d6f0526', 'rsrc/css/aphront/multi-column.css' => '84cc6640', @@ -245,7 +245,7 @@ 'rsrc/externals/javelin/lib/Sound.js' => '949c0fe5', 'rsrc/externals/javelin/lib/URI.js' => 'c989ade3', 'rsrc/externals/javelin/lib/Vector.js' => '2caa8fb8', - 'rsrc/externals/javelin/lib/WebSocket.js' => 'e292eaf4', + 'rsrc/externals/javelin/lib/WebSocket.js' => '0c4969d6', 'rsrc/externals/javelin/lib/Workflow.js' => '1e911d0f', 'rsrc/externals/javelin/lib/__tests__/Cookie.js' => '5ed109e8', 'rsrc/externals/javelin/lib/__tests__/DOM.js' => 'c984504b', @@ -361,7 +361,7 @@ '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' => '5359e785', + 'rsrc/js/application/aphlict/Aphlict.js' => 'ce5f793f', 'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => 'caade6f2', 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'd82b1ff9', 'rsrc/js/application/aphlict/behavior-aphlict-status.js' => '5e2634b9', @@ -522,7 +522,7 @@ 'rsrc/js/core/behavior-workflow.js' => '0a3f3021', 'rsrc/js/core/darkconsole/DarkLog.js' => 'c8e1ffe3', 'rsrc/js/core/darkconsole/DarkMessage.js' => 'c48cccdd', - 'rsrc/js/core/darkconsole/behavior-dark-console.js' => '3725c90c', + 'rsrc/js/core/darkconsole/behavior-dark-console.js' => '698614f9', 'rsrc/js/core/phtize.js' => 'd254d646', 'rsrc/js/phui/behavior-phui-dropdown-menu.js' => 'b95d6f7d', 'rsrc/js/phui/behavior-phui-file-upload.js' => 'b003d4fb', @@ -538,7 +538,7 @@ 'symbols' => array( 'almanac-css' => 'dbb9b3af', 'aphront-bars' => '231ac33c', - 'aphront-dark-console-css' => '07dd8d38', + 'aphront-dark-console-css' => 'e7c6e44d', 'aphront-dialog-view-css' => '685c7e2d', 'aphront-list-filter-view-css' => '5d6f0526', 'aphront-multi-column-view-css' => '84cc6640', @@ -583,7 +583,7 @@ 'herald-rule-editor' => 'd6a7e717', 'herald-test-css' => 'a52e323e', 'inline-comment-summary-css' => '51efda3a', - 'javelin-aphlict' => '5359e785', + 'javelin-aphlict' => 'ce5f793f', 'javelin-behavior' => '61cbc29a', 'javelin-behavior-aphlict-dropdown' => 'caade6f2', 'javelin-behavior-aphlict-listen' => 'd82b1ff9', @@ -605,7 +605,7 @@ 'javelin-behavior-conpherence-pontificate' => '55616e04', 'javelin-behavior-conpherence-search' => '9bbf3762', 'javelin-behavior-countdown-timer' => 'e4cc26b3', - 'javelin-behavior-dark-console' => '3725c90c', + 'javelin-behavior-dark-console' => '698614f9', 'javelin-behavior-dashboard-async-panel' => '469c0d9e', 'javelin-behavior-dashboard-move-panels' => '408bf173', 'javelin-behavior-dashboard-query-panel-select' => '453c5375', @@ -753,7 +753,7 @@ 'javelin-view-interpreter' => 'f829edb3', 'javelin-view-renderer' => '6c2b09a2', 'javelin-view-visitor' => 'efe49472', - 'javelin-websocket' => 'e292eaf4', + 'javelin-websocket' => '0c4969d6', 'javelin-workboard-board' => '8935deef', 'javelin-workboard-card' => 'c587b80f', 'javelin-workboard-column' => '21df4ff5', @@ -981,6 +981,9 @@ 'javelin-dom', 'javelin-router', ), + '0c4969d6' => array( + 'javelin-install', + ), '0ca788bd' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1122,16 +1125,6 @@ 'javelin-dom', 'javelin-workflow', ), - '3725c90c' => array( - 'javelin-behavior', - 'javelin-stratcom', - 'javelin-util', - 'javelin-dom', - 'javelin-request', - 'phabricator-keyboard-shortcut', - 'phabricator-darklog', - 'phabricator-darkmessage', - ), '3ab51e2c' => array( 'javelin-behavior', 'javelin-behavior-device', @@ -1294,13 +1287,6 @@ '5294060f' => array( 'phui-theme-css', ), - '5359e785' => array( - 'javelin-install', - 'javelin-util', - 'javelin-websocket', - 'javelin-leader', - 'javelin-json', - ), '54b612ba' => array( 'javelin-color', 'javelin-install', @@ -1395,6 +1381,16 @@ '6882e80a' => array( 'javelin-dom', ), + '698614f9' => array( + 'javelin-behavior', + 'javelin-stratcom', + 'javelin-util', + 'javelin-dom', + 'javelin-request', + 'phabricator-keyboard-shortcut', + 'phabricator-darklog', + 'phabricator-darkmessage', + ), '69adf288' => array( 'javelin-install', ), @@ -2018,6 +2014,13 @@ 'cd2b9b77' => array( 'phui-oi-list-view-css', ), + 'ce5f793f' => array( + 'javelin-install', + 'javelin-util', + 'javelin-websocket', + 'javelin-leader', + 'javelin-json', + ), 'd0c516d5' => array( 'javelin-behavior', 'javelin-dom', @@ -2128,9 +2131,6 @@ 'javelin-stratcom', 'javelin-dom', ), - 'e292eaf4' => array( - 'javelin-install', - ), 'e2e0a072' => array( 'javelin-behavior', 'javelin-stratcom', diff --git a/src/applications/console/plugin/DarkConsoleRealtimePlugin.php b/src/applications/console/plugin/DarkConsoleRealtimePlugin.php --- a/src/applications/console/plugin/DarkConsoleRealtimePlugin.php +++ b/src/applications/console/plugin/DarkConsoleRealtimePlugin.php @@ -15,12 +15,41 @@ } public function renderPanel() { - return phutil_tag( + $frame = phutil_tag( 'div', array( 'id' => 'dark-console-realtime-log', 'class' => 'dark-console-log-frame', )); + + $reconnect_label = pht('Reconnect'); + + $buttons = phutil_tag( + 'div', + array( + 'class' => 'dark-console-realtime-actions', + ), + array( + id(new PHUIButtonView()) + ->setIcon('fa-refresh') + ->setColor(PHUIButtonView::GREY) + ->setText($reconnect_label) + ->addSigil('dark-console-realtime-action') + ->setMetadata( + array( + 'action' => 'reconnect', + 'label' => $reconnect_label, + )), + )); + + return phutil_tag( + 'div', + array( + ), + array( + $buttons, + $frame, + )); } } diff --git a/webroot/rsrc/css/aphront/dark-console.css b/webroot/rsrc/css/aphront/dark-console.css --- a/webroot/rsrc/css/aphront/dark-console.css +++ b/webroot/rsrc/css/aphront/dark-console.css @@ -223,7 +223,7 @@ overflow: auto; background: #303030; border: 1px solid #202020; - margin: 4px; + margin: 8px 0; } .dark-console-log-message { diff --git a/webroot/rsrc/externals/javelin/lib/WebSocket.js b/webroot/rsrc/externals/javelin/lib/WebSocket.js --- a/webroot/rsrc/externals/javelin/lib/WebSocket.js +++ b/webroot/rsrc/externals/javelin/lib/WebSocket.js @@ -105,6 +105,26 @@ /** + * Disconnect abruptly, prompting a reconnect. + */ + reconnect: function() { + if (!this._isOpen) { + return; + } + + this._socket.close(); + }, + + + /** + * Get the current reconnect delay (in milliseconds). + */ + getReconnectDelay: function() { + return this._delayUntilReconnect; + }, + + + /** * Callback for connection open. */ _onopen: function() { diff --git a/webroot/rsrc/js/application/aphlict/Aphlict.js b/webroot/rsrc/js/application/aphlict/Aphlict.js --- a/webroot/rsrc/js/application/aphlict/Aphlict.js +++ b/webroot/rsrc/js/application/aphlict/Aphlict.js @@ -71,6 +71,10 @@ return this._status; }, + getWebsocket: function() { + return this._socket; + }, + _begin: function() { JX.Leader.broadcast( null, diff --git a/webroot/rsrc/js/core/darkconsole/behavior-dark-console.js b/webroot/rsrc/js/core/darkconsole/behavior-dark-console.js --- a/webroot/rsrc/js/core/darkconsole/behavior-dark-console.js +++ b/webroot/rsrc/js/core/darkconsole/behavior-dark-console.js @@ -353,12 +353,49 @@ JX.Leader.listen('onReceiveBroadcast', function(message, is_leader) { var json = JX.JSON.stringify(message.data); + + if (message.type == 'aphlict.status') { + if (message.data == 'closed') { + var ws = JX.Aphlict.getInstance().getWebsocket(); + if (ws) { + var delay = ws.getReconnectDelay(); + json += ' [Reconnect: ' + delay + 'ms]'; + } + } + } + leader_log('onReceiveBroadcast', message.type, is_leader, json); }); JX.Leader.listen('onBecomeLeader', function() { leader_log('onBecomeLeader'); }); + + var action_log = function(action) { + var message = new JX.DarkMessage() + .setMessage('> ' + action); + + realtime_log.addMessage(message); + }; + + JX.Stratcom.listen('click', 'dark-console-realtime-action', function(e) { + var node = e.getNode('dark-console-realtime-action'); + var data = JX.Stratcom.getData(node); + + action_log(data.label); + + var action = data.action; + switch (action) { + case 'reconnect': + var ws = JX.Aphlict.getInstance().getWebsocket(); + if (ws) { + ws.reconnect(); + } + break; + } + + }); + } });