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' => '437d3b5a', 'conpherence.pkg.js' => '281b1a73', 'core.pkg.css' => 'b2ad82f4', - 'core.pkg.js' => 'deabcef7', - 'darkconsole.pkg.js' => 'e7393ebb', + 'core.pkg.js' => '291eb50e', + 'darkconsole.pkg.js' => '061371d8', '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' => 'f54bf286', + 'rsrc/css/aphront/dark-console.css' => '07dd8d38', 'rsrc/css/aphront/dialog-view.css' => '685c7e2d', 'rsrc/css/aphront/list-filter-view.css' => '5d6f0526', 'rsrc/css/aphront/multi-column.css' => '84cc6640', @@ -363,7 +363,7 @@ 'rsrc/image/texture/table_header_tall.png' => 'd56b434f', 'rsrc/js/application/aphlict/Aphlict.js' => '5359e785', 'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => 'caade6f2', - 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'fb20ac8d', + 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'd82b1ff9', 'rsrc/js/application/aphlict/behavior-aphlict-status.js' => '5e2634b9', 'rsrc/js/application/aphlict/behavior-desktop-notifications-control.js' => 'd5a2d665', 'rsrc/js/application/calendar/behavior-day-view.js' => '4b3c4443', @@ -482,7 +482,6 @@ 'rsrc/js/core/behavior-autofocus.js' => '7319e029', 'rsrc/js/core/behavior-badge-view.js' => '8ff5e24c', 'rsrc/js/core/behavior-choose-control.js' => '327a00d1', - 'rsrc/js/core/behavior-dark-console.js' => 'f411b6ae', 'rsrc/js/core/behavior-detect-timezone.js' => '4c193c96', 'rsrc/js/core/behavior-device.js' => 'bb1dd507', 'rsrc/js/core/behavior-drag-and-drop-textarea.js' => '484a6e22', @@ -521,6 +520,9 @@ 'rsrc/js/core/behavior-user-menu.js' => '31420f77', 'rsrc/js/core/behavior-watch-anchor.js' => '9f36c42d', '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/phtize.js' => 'd254d646', 'rsrc/js/phui/behavior-phui-dropdown-menu.js' => 'b95d6f7d', 'rsrc/js/phui/behavior-phui-file-upload.js' => 'b003d4fb', @@ -536,7 +538,7 @@ 'symbols' => array( 'almanac-css' => 'dbb9b3af', 'aphront-bars' => '231ac33c', - 'aphront-dark-console-css' => 'f54bf286', + 'aphront-dark-console-css' => '07dd8d38', 'aphront-dialog-view-css' => '685c7e2d', 'aphront-list-filter-view-css' => '5d6f0526', 'aphront-multi-column-view-css' => '84cc6640', @@ -584,7 +586,7 @@ 'javelin-aphlict' => '5359e785', 'javelin-behavior' => '61cbc29a', 'javelin-behavior-aphlict-dropdown' => 'caade6f2', - 'javelin-behavior-aphlict-listen' => 'fb20ac8d', + 'javelin-behavior-aphlict-listen' => 'd82b1ff9', 'javelin-behavior-aphlict-status' => '5e2634b9', 'javelin-behavior-aphront-basic-tokenizer' => 'b3a4b884', 'javelin-behavior-aphront-drag-and-drop-textarea' => '484a6e22', @@ -603,7 +605,7 @@ 'javelin-behavior-conpherence-pontificate' => '55616e04', 'javelin-behavior-conpherence-search' => '9bbf3762', 'javelin-behavior-countdown-timer' => 'e4cc26b3', - 'javelin-behavior-dark-console' => 'f411b6ae', + 'javelin-behavior-dark-console' => '3725c90c', 'javelin-behavior-dashboard-async-panel' => '469c0d9e', 'javelin-behavior-dashboard-move-panels' => '408bf173', 'javelin-behavior-dashboard-query-panel-select' => '453c5375', @@ -774,6 +776,8 @@ 'phabricator-content-source-view-css' => '4b8b05d4', 'phabricator-core-css' => '9f4cb463', 'phabricator-countdown-css' => '16c52f5c', + 'phabricator-darklog' => 'c8e1ffe3', + 'phabricator-darkmessage' => 'c48cccdd', 'phabricator-dashboard-css' => 'fe5b1869', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', @@ -1118,6 +1122,16 @@ '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', @@ -2066,6 +2080,20 @@ 'javelin-dom', 'phabricator-draggable-list', ), + 'd82b1ff9' => array( + 'javelin-behavior', + 'javelin-aphlict', + 'javelin-stratcom', + 'javelin-request', + 'javelin-uri', + 'javelin-dom', + 'javelin-json', + 'javelin-router', + 'javelin-util', + 'javelin-leader', + 'javelin-sound', + 'phabricator-notification', + ), 'd835b03a' => array( 'javelin-behavior', 'javelin-dom', @@ -2173,14 +2201,6 @@ 'f12cbc9f' => array( 'phui-oi-list-view-css', ), - 'f411b6ae' => array( - 'javelin-behavior', - 'javelin-stratcom', - 'javelin-util', - 'javelin-dom', - 'javelin-request', - 'phabricator-keyboard-shortcut', - ), 'f50152ad' => array( 'phui-timeline-view-css', ), @@ -2203,20 +2223,6 @@ 'javelin-install', 'javelin-dom', ), - 'fb20ac8d' => array( - 'javelin-behavior', - 'javelin-aphlict', - 'javelin-stratcom', - 'javelin-request', - 'javelin-uri', - 'javelin-dom', - 'javelin-json', - 'javelin-router', - 'javelin-util', - 'javelin-leader', - 'javelin-sound', - 'phabricator-notification', - ), 'fbe497e7' => array( 'javelin-behavior', 'javelin-util', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -349,6 +349,7 @@ 'DarkConsoleEventPlugin' => 'applications/console/plugin/DarkConsoleEventPlugin.php', 'DarkConsoleEventPluginAPI' => 'applications/console/plugin/event/DarkConsoleEventPluginAPI.php', 'DarkConsolePlugin' => 'applications/console/plugin/DarkConsolePlugin.php', + 'DarkConsoleRealtimePlugin' => 'applications/console/plugin/DarkConsoleRealtimePlugin.php', 'DarkConsoleRequestPlugin' => 'applications/console/plugin/DarkConsoleRequestPlugin.php', 'DarkConsoleServicesPlugin' => 'applications/console/plugin/DarkConsoleServicesPlugin.php', 'DarkConsoleStartupPlugin' => 'applications/console/plugin/DarkConsoleStartupPlugin.php', @@ -5144,6 +5145,7 @@ 'DarkConsoleEventPlugin' => 'DarkConsolePlugin', 'DarkConsoleEventPluginAPI' => 'PhabricatorEventListener', 'DarkConsolePlugin' => 'Phobject', + 'DarkConsoleRealtimePlugin' => 'DarkConsolePlugin', 'DarkConsoleRequestPlugin' => 'DarkConsolePlugin', 'DarkConsoleServicesPlugin' => 'DarkConsolePlugin', 'DarkConsoleStartupPlugin' => 'DarkConsolePlugin', diff --git a/src/applications/console/plugin/DarkConsoleRealtimePlugin.php b/src/applications/console/plugin/DarkConsoleRealtimePlugin.php new file mode 100644 --- /dev/null +++ b/src/applications/console/plugin/DarkConsoleRealtimePlugin.php @@ -0,0 +1,26 @@ + 'dark-console-realtime-log', + 'class' => 'dark-console-log-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 @@ -217,3 +217,17 @@ .dark-console-panel-error-details { display: none; } + +.dark-console-log-frame { + height: 500px; + overflow: auto; + background: #303030; + border: 1px solid #202020; + margin: 4px; +} + +.dark-console-log-message { + background: #404040; + padding: 8px; + margin: 2px; +} diff --git a/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js b/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js --- a/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js +++ b/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js @@ -114,9 +114,16 @@ config.websocketURI, config.subscriptions); - client - .setHandler(onAphlictMessage) - .start(); + var start_client = function() { + client + .setHandler(onAphlictMessage) + .start(); + }; + + // Don't start the client until other behaviors have had a chance to + // initialize. In particular, we want to capture events into the log for + // the DarkConsole "Realtime" panel. + setTimeout(start_client, 0); JX.Stratcom.listen( 'quicksand-redraw', diff --git a/webroot/rsrc/js/core/darkconsole/DarkLog.js b/webroot/rsrc/js/core/darkconsole/DarkLog.js new file mode 100644 --- /dev/null +++ b/webroot/rsrc/js/core/darkconsole/DarkLog.js @@ -0,0 +1,47 @@ +/** + * @provides phabricator-darklog + * @javelin + */ + +JX.install('DarkLog', { + + construct: function() { + this._messages = []; + }, + + members: { + _node: null, + _messages: null, + + addMessage: function(message) { + var node = message.getNode(); + + this._messages.push(message); + if (this._node) { + this._append([node]); + } + + return this; + }, + + setNode: function(node) { + var nodes = []; + for (var ii = 0; ii < this._messages.length; ii++) { + nodes.push(this._messages[ii].getNode()); + } + + this._node = node; + this._append(nodes); + + return this; + }, + + _append: function(nodes) { + for (var ii = 0; ii < nodes.length; ii++) { + this._node.appendChild(nodes[ii]); + } + } + + } + +}); diff --git a/webroot/rsrc/js/core/darkconsole/DarkMessage.js b/webroot/rsrc/js/core/darkconsole/DarkMessage.js new file mode 100644 --- /dev/null +++ b/webroot/rsrc/js/core/darkconsole/DarkMessage.js @@ -0,0 +1,37 @@ +/** + * @provides phabricator-darkmessage + * @javelin + */ + +JX.install('DarkMessage', { + + construct: function() { + + }, + + members: { + _node: null, + _message: null, + + setMessage: function(message) { + this._message = message; + + JX.DOM.setContent(this.getNode(), message); + + return this; + }, + + getNode: function() { + if (!this._node) { + this._node = JX.$N( + 'div', + { + className: 'dark-console-log-message' + }); + } + + return this._node; + } + } + +}); diff --git a/webroot/rsrc/js/core/behavior-dark-console.js b/webroot/rsrc/js/core/darkconsole/behavior-dark-console.js rename from webroot/rsrc/js/core/behavior-dark-console.js rename to webroot/rsrc/js/core/darkconsole/behavior-dark-console.js --- a/webroot/rsrc/js/core/behavior-dark-console.js +++ b/webroot/rsrc/js/core/darkconsole/behavior-dark-console.js @@ -6,6 +6,8 @@ * javelin-dom * javelin-request * phabricator-keyboard-shortcut + * phabricator-darklog + * phabricator-darkmessage */ JX.behavior('dark-console', function(config, statics) { @@ -246,6 +248,12 @@ var div = JX.$N('div', {className: 'dark-console-panel-core'}, JX.$H(html)); JX.DOM.setContent(statics.el.panel, div); + + var params = { + panel: tclass + }; + + JX.Stratcom.invoke('darkconsole.draw', null, params); } function install_shortcut() { @@ -287,4 +295,70 @@ } add_request(config); + +/* -( Realtime Panel )----------------------------------------------------- */ + + + if (!statics.realtime) { + statics.realtime = true; + + var realtime_log = new JX.DarkLog(); + var realtime_id = 'dark-console-realtime-log'; + + JX.Stratcom.listen('darkconsole.draw', null, function(e) { + var data = e.getData(); + if (data.panel != 'DarkConsoleRealtimePlugin') { + return; + } + + var node = JX.$(realtime_id); + realtime_log.setNode(node); + }); + + // If the panel is initially visible, try rendering. + try { + var node = JX.$(realtime_id); + realtime_log.setNode(node); + } catch (exception) { + // Ignore. + } + + var leader_log = function(event_name, type, is_leader, details) { + var parts = []; + if (is_leader === true) { + parts.push('+'); + } else if (is_leader === false) { + parts.push('-'); + } else { + parts.push('~'); + } + + parts.push('[Leader/' + event_name + ']'); + + if (type) { + parts.push('(' + type + ')'); + } + + if (details) { + parts.push(details); + } + + parts = parts.join(' '); + + var message = new JX.DarkMessage() + .setMessage(parts); + + realtime_log.addMessage(message); + }; + + JX.Leader.listen('onReceiveBroadcast', function(message, is_leader) { + var json = JX.JSON.stringify(message.data); + leader_log('onReceiveBroadcast', message.type, is_leader, json); + }); + + JX.Leader.listen('onBecomeLeader', function() { + leader_log('onBecomeLeader'); + }); + } + });