mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 06:42:42 +01:00
DarkConsole: fix rendering, move request log, load over ajax
Summary: This accomplishes three major goals: # Fixes phutil_render_tag -> phutil_tag callsites in DarkConsole. # Moves the Ajax request log to a new panel on the left. This panel (and the tabs panel) get scrollbars when they get large, instead of making the page constantly scroll down. # Loads the panel content over ajax, instead of dumping it into the page body / ajax response body. I've been planning to do this for about 3 years, which is why the plugins are architected the way they are. This should make debugging easier by making response bodies not be 50%+ darkconsole stuff. Additionally, load the plugins dynamically (the old method predates library maps and PhutilSymbolLoader). Test Plan: {F30675} - Switched between requests and tabs, reloaded page, saw same tab. - Used "analyze queries", "profile page", triggered errors. - Verified page does not load anything by default if dark console is closed with Charles. - Generally banged on it a bit. Reviewers: vrana, btrahan, chad Reviewed By: vrana CC: aran Maniphest Tasks: T2432 Differential Revision: https://secure.phabricator.com/D4692
This commit is contained in:
parent
9a0ae6376f
commit
114ed6c7fe
18 changed files with 560 additions and 481 deletions
|
@ -166,7 +166,6 @@ $package_spec = array(
|
|||
'javelin-behavior-maniphest-subpriority-editor',
|
||||
),
|
||||
'darkconsole.pkg.js' => array(
|
||||
'javelin-behavior-dark-console-ajax',
|
||||
'javelin-behavior-dark-console',
|
||||
'javelin-behavior-error-log',
|
||||
),
|
||||
|
|
|
@ -42,6 +42,13 @@ celerity_register_resource_map(array(
|
|||
'disk' => '/rsrc/image/credit_cards.png',
|
||||
'type' => 'png',
|
||||
),
|
||||
'/rsrc/image/darkload.gif' =>
|
||||
array(
|
||||
'hash' => '3a52cb7145d6e70f461fed21273117f2',
|
||||
'uri' => '/res/3a52cb71/rsrc/image/darkload.gif',
|
||||
'disk' => '/rsrc/image/darkload.gif',
|
||||
'type' => 'gif',
|
||||
),
|
||||
'/rsrc/image/divot.png' =>
|
||||
array(
|
||||
'hash' => '3be267bd11ea375bf68e808893718e0e',
|
||||
|
@ -598,7 +605,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'aphront-dark-console-css' =>
|
||||
array(
|
||||
'uri' => '/res/1e1f78d4/rsrc/css/aphront/dark-console.css',
|
||||
'uri' => '/res/63841304/rsrc/css/aphront/dark-console.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -1057,7 +1064,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'javelin-behavior-aphront-form-disable-on-submit' =>
|
||||
array(
|
||||
'uri' => '/res/ca54e8b9/rsrc/js/application/core/behavior-form.js',
|
||||
'uri' => '/res/70fd43fd/rsrc/js/application/core/behavior-form.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -1145,7 +1152,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'javelin-behavior-dark-console' =>
|
||||
array(
|
||||
'uri' => '/res/aa6f8a71/rsrc/js/application/core/behavior-dark-console.js',
|
||||
'uri' => '/res/c3e8a3d8/rsrc/js/application/core/behavior-dark-console.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -1155,21 +1162,9 @@ celerity_register_resource_map(array(
|
|||
3 => 'javelin-dom',
|
||||
4 => 'javelin-request',
|
||||
5 => 'phabricator-keyboard-shortcut',
|
||||
6 => 'javelin-behavior-dark-console-ajax',
|
||||
),
|
||||
'disk' => '/rsrc/js/application/core/behavior-dark-console.js',
|
||||
),
|
||||
'javelin-behavior-dark-console-ajax' =>
|
||||
array(
|
||||
'uri' => '/res/ac3ab63a/rsrc/js/application/core/behavior-dark-console-ajax.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-dom',
|
||||
),
|
||||
'disk' => '/rsrc/js/application/core/behavior-dark-console-ajax.js',
|
||||
),
|
||||
'javelin-behavior-device' =>
|
||||
array(
|
||||
'uri' => '/res/a10b851b/rsrc/js/application/core/behavior-device.js',
|
||||
|
@ -1493,7 +1488,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'javelin-behavior-lightbox-attachments' =>
|
||||
array(
|
||||
'uri' => '/res/5efba371/rsrc/js/application/core/behavior-lightbox-attachments.js',
|
||||
'uri' => '/res/08f5e202/rsrc/js/application/core/behavior-lightbox-attachments.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -1986,7 +1981,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'javelin-dom' =>
|
||||
array(
|
||||
'uri' => '/res/2826c532/rsrc/js/javelin/lib/DOM.js',
|
||||
'uri' => '/res/459f3c08/rsrc/js/javelin/lib/DOM.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -3393,7 +3388,7 @@ celerity_register_resource_map(array(
|
|||
'uri' => '/res/pkg/023adc14/core.pkg.css',
|
||||
'type' => 'css',
|
||||
),
|
||||
'66dca903' =>
|
||||
'b3c1b6e7' =>
|
||||
array(
|
||||
'name' => 'core.pkg.js',
|
||||
'symbols' =>
|
||||
|
@ -3432,19 +3427,18 @@ celerity_register_resource_map(array(
|
|||
31 => 'javelin-behavior-global-drag-and-drop',
|
||||
32 => 'javelin-behavior-phabricator-home-reveal-tiles',
|
||||
),
|
||||
'uri' => '/res/pkg/66dca903/core.pkg.js',
|
||||
'uri' => '/res/pkg/b3c1b6e7/core.pkg.js',
|
||||
'type' => 'js',
|
||||
),
|
||||
'8edbada5' =>
|
||||
'032118cf' =>
|
||||
array(
|
||||
'name' => 'darkconsole.pkg.js',
|
||||
'symbols' =>
|
||||
array(
|
||||
0 => 'javelin-behavior-dark-console-ajax',
|
||||
1 => 'javelin-behavior-dark-console',
|
||||
2 => 'javelin-behavior-error-log',
|
||||
0 => 'javelin-behavior-dark-console',
|
||||
1 => 'javelin-behavior-error-log',
|
||||
),
|
||||
'uri' => '/res/pkg/8edbada5/darkconsole.pkg.js',
|
||||
'uri' => '/res/pkg/032118cf/darkconsole.pkg.js',
|
||||
'type' => 'js',
|
||||
),
|
||||
'ec01d039' =>
|
||||
|
@ -3521,7 +3515,7 @@ celerity_register_resource_map(array(
|
|||
'uri' => '/res/pkg/f96657b8/diffusion.pkg.js',
|
||||
'type' => 'js',
|
||||
),
|
||||
'fbeded59' =>
|
||||
'1c6f020b' =>
|
||||
array(
|
||||
'name' => 'javelin.pkg.js',
|
||||
'symbols' =>
|
||||
|
@ -3546,7 +3540,7 @@ celerity_register_resource_map(array(
|
|||
17 => 'javelin-typeahead-ondemand-source',
|
||||
18 => 'javelin-tokenizer',
|
||||
),
|
||||
'uri' => '/res/pkg/fbeded59/javelin.pkg.js',
|
||||
'uri' => '/res/pkg/1c6f020b/javelin.pkg.js',
|
||||
'type' => 'js',
|
||||
),
|
||||
'e30a3fa8' =>
|
||||
|
@ -3608,18 +3602,17 @@ celerity_register_resource_map(array(
|
|||
'diffusion-icons-css' => 'c8ce2d88',
|
||||
'global-drag-and-drop-css' => '023adc14',
|
||||
'inline-comment-summary-css' => 'ec01d039',
|
||||
'javelin-aphlict' => '66dca903',
|
||||
'javelin-behavior' => 'fbeded59',
|
||||
'javelin-behavior-aphlict-dropdown' => '66dca903',
|
||||
'javelin-behavior-aphlict-listen' => '66dca903',
|
||||
'javelin-behavior-aphront-basic-tokenizer' => '66dca903',
|
||||
'javelin-aphlict' => 'b3c1b6e7',
|
||||
'javelin-behavior' => '1c6f020b',
|
||||
'javelin-behavior-aphlict-dropdown' => 'b3c1b6e7',
|
||||
'javelin-behavior-aphlict-listen' => 'b3c1b6e7',
|
||||
'javelin-behavior-aphront-basic-tokenizer' => 'b3c1b6e7',
|
||||
'javelin-behavior-aphront-drag-and-drop' => '310cd201',
|
||||
'javelin-behavior-aphront-drag-and-drop-textarea' => '310cd201',
|
||||
'javelin-behavior-aphront-form-disable-on-submit' => '66dca903',
|
||||
'javelin-behavior-aphront-form-disable-on-submit' => 'b3c1b6e7',
|
||||
'javelin-behavior-audit-preview' => 'f96657b8',
|
||||
'javelin-behavior-dark-console' => '8edbada5',
|
||||
'javelin-behavior-dark-console-ajax' => '8edbada5',
|
||||
'javelin-behavior-device' => '66dca903',
|
||||
'javelin-behavior-dark-console' => '032118cf',
|
||||
'javelin-behavior-device' => 'b3c1b6e7',
|
||||
'javelin-behavior-differential-accept-with-errors' => '310cd201',
|
||||
'javelin-behavior-differential-add-reviewers-and-ccs' => '310cd201',
|
||||
'javelin-behavior-differential-comment-jump' => '310cd201',
|
||||
|
@ -3634,84 +3627,84 @@ celerity_register_resource_map(array(
|
|||
'javelin-behavior-differential-user-select' => '310cd201',
|
||||
'javelin-behavior-diffusion-commit-graph' => 'f96657b8',
|
||||
'javelin-behavior-diffusion-pull-lastmodified' => 'f96657b8',
|
||||
'javelin-behavior-error-log' => '8edbada5',
|
||||
'javelin-behavior-global-drag-and-drop' => '66dca903',
|
||||
'javelin-behavior-konami' => '66dca903',
|
||||
'javelin-behavior-lightbox-attachments' => '66dca903',
|
||||
'javelin-behavior-error-log' => '032118cf',
|
||||
'javelin-behavior-global-drag-and-drop' => 'b3c1b6e7',
|
||||
'javelin-behavior-konami' => 'b3c1b6e7',
|
||||
'javelin-behavior-lightbox-attachments' => 'b3c1b6e7',
|
||||
'javelin-behavior-maniphest-batch-selector' => '7707de41',
|
||||
'javelin-behavior-maniphest-subpriority-editor' => '7707de41',
|
||||
'javelin-behavior-maniphest-transaction-controls' => '7707de41',
|
||||
'javelin-behavior-maniphest-transaction-expand' => '7707de41',
|
||||
'javelin-behavior-maniphest-transaction-preview' => '7707de41',
|
||||
'javelin-behavior-phabricator-active-nav' => '66dca903',
|
||||
'javelin-behavior-phabricator-autofocus' => '66dca903',
|
||||
'javelin-behavior-phabricator-home-reveal-tiles' => '66dca903',
|
||||
'javelin-behavior-phabricator-keyboard-shortcuts' => '66dca903',
|
||||
'javelin-behavior-phabricator-nav' => '66dca903',
|
||||
'javelin-behavior-phabricator-active-nav' => 'b3c1b6e7',
|
||||
'javelin-behavior-phabricator-autofocus' => 'b3c1b6e7',
|
||||
'javelin-behavior-phabricator-home-reveal-tiles' => 'b3c1b6e7',
|
||||
'javelin-behavior-phabricator-keyboard-shortcuts' => 'b3c1b6e7',
|
||||
'javelin-behavior-phabricator-nav' => 'b3c1b6e7',
|
||||
'javelin-behavior-phabricator-object-selector' => '310cd201',
|
||||
'javelin-behavior-phabricator-oncopy' => '66dca903',
|
||||
'javelin-behavior-phabricator-remarkup-assist' => '66dca903',
|
||||
'javelin-behavior-phabricator-search-typeahead' => '66dca903',
|
||||
'javelin-behavior-phabricator-tooltips' => '66dca903',
|
||||
'javelin-behavior-phabricator-watch-anchor' => '66dca903',
|
||||
'javelin-behavior-refresh-csrf' => '66dca903',
|
||||
'javelin-behavior-phabricator-oncopy' => 'b3c1b6e7',
|
||||
'javelin-behavior-phabricator-remarkup-assist' => 'b3c1b6e7',
|
||||
'javelin-behavior-phabricator-search-typeahead' => 'b3c1b6e7',
|
||||
'javelin-behavior-phabricator-tooltips' => 'b3c1b6e7',
|
||||
'javelin-behavior-phabricator-watch-anchor' => 'b3c1b6e7',
|
||||
'javelin-behavior-refresh-csrf' => 'b3c1b6e7',
|
||||
'javelin-behavior-repository-crossreference' => '310cd201',
|
||||
'javelin-behavior-toggle-class' => '66dca903',
|
||||
'javelin-behavior-workflow' => '66dca903',
|
||||
'javelin-dom' => 'fbeded59',
|
||||
'javelin-event' => 'fbeded59',
|
||||
'javelin-install' => 'fbeded59',
|
||||
'javelin-json' => 'fbeded59',
|
||||
'javelin-mask' => 'fbeded59',
|
||||
'javelin-request' => 'fbeded59',
|
||||
'javelin-resource' => 'fbeded59',
|
||||
'javelin-stratcom' => 'fbeded59',
|
||||
'javelin-tokenizer' => 'fbeded59',
|
||||
'javelin-typeahead' => 'fbeded59',
|
||||
'javelin-typeahead-normalizer' => 'fbeded59',
|
||||
'javelin-typeahead-ondemand-source' => 'fbeded59',
|
||||
'javelin-typeahead-preloaded-source' => 'fbeded59',
|
||||
'javelin-typeahead-source' => 'fbeded59',
|
||||
'javelin-uri' => 'fbeded59',
|
||||
'javelin-util' => 'fbeded59',
|
||||
'javelin-vector' => 'fbeded59',
|
||||
'javelin-workflow' => 'fbeded59',
|
||||
'javelin-behavior-toggle-class' => 'b3c1b6e7',
|
||||
'javelin-behavior-workflow' => 'b3c1b6e7',
|
||||
'javelin-dom' => '1c6f020b',
|
||||
'javelin-event' => '1c6f020b',
|
||||
'javelin-install' => '1c6f020b',
|
||||
'javelin-json' => '1c6f020b',
|
||||
'javelin-mask' => '1c6f020b',
|
||||
'javelin-request' => '1c6f020b',
|
||||
'javelin-resource' => '1c6f020b',
|
||||
'javelin-stratcom' => '1c6f020b',
|
||||
'javelin-tokenizer' => '1c6f020b',
|
||||
'javelin-typeahead' => '1c6f020b',
|
||||
'javelin-typeahead-normalizer' => '1c6f020b',
|
||||
'javelin-typeahead-ondemand-source' => '1c6f020b',
|
||||
'javelin-typeahead-preloaded-source' => '1c6f020b',
|
||||
'javelin-typeahead-source' => '1c6f020b',
|
||||
'javelin-uri' => '1c6f020b',
|
||||
'javelin-util' => '1c6f020b',
|
||||
'javelin-vector' => '1c6f020b',
|
||||
'javelin-workflow' => '1c6f020b',
|
||||
'lightbox-attachment-css' => '023adc14',
|
||||
'maniphest-task-summary-css' => 'e30a3fa8',
|
||||
'maniphest-transaction-detail-css' => 'e30a3fa8',
|
||||
'phabricator-busy' => '66dca903',
|
||||
'phabricator-busy' => 'b3c1b6e7',
|
||||
'phabricator-content-source-view-css' => 'ec01d039',
|
||||
'phabricator-core-buttons-css' => '023adc14',
|
||||
'phabricator-core-css' => '023adc14',
|
||||
'phabricator-crumbs-view-css' => '023adc14',
|
||||
'phabricator-directory-css' => '023adc14',
|
||||
'phabricator-drag-and-drop-file-upload' => '310cd201',
|
||||
'phabricator-dropdown-menu' => '66dca903',
|
||||
'phabricator-file-upload' => '66dca903',
|
||||
'phabricator-dropdown-menu' => 'b3c1b6e7',
|
||||
'phabricator-file-upload' => 'b3c1b6e7',
|
||||
'phabricator-filetree-view-css' => '023adc14',
|
||||
'phabricator-flag-css' => '023adc14',
|
||||
'phabricator-form-view-css' => '023adc14',
|
||||
'phabricator-header-view-css' => '023adc14',
|
||||
'phabricator-jump-nav' => '023adc14',
|
||||
'phabricator-keyboard-shortcut' => '66dca903',
|
||||
'phabricator-keyboard-shortcut-manager' => '66dca903',
|
||||
'phabricator-keyboard-shortcut' => 'b3c1b6e7',
|
||||
'phabricator-keyboard-shortcut-manager' => 'b3c1b6e7',
|
||||
'phabricator-main-menu-view' => '023adc14',
|
||||
'phabricator-menu-item' => '66dca903',
|
||||
'phabricator-menu-item' => 'b3c1b6e7',
|
||||
'phabricator-nav-view-css' => '023adc14',
|
||||
'phabricator-notification' => '66dca903',
|
||||
'phabricator-notification' => 'b3c1b6e7',
|
||||
'phabricator-notification-css' => '023adc14',
|
||||
'phabricator-notification-menu-css' => '023adc14',
|
||||
'phabricator-object-item-list-view-css' => '023adc14',
|
||||
'phabricator-object-selector-css' => 'ec01d039',
|
||||
'phabricator-paste-file-upload' => '66dca903',
|
||||
'phabricator-prefab' => '66dca903',
|
||||
'phabricator-paste-file-upload' => 'b3c1b6e7',
|
||||
'phabricator-prefab' => 'b3c1b6e7',
|
||||
'phabricator-project-tag-css' => 'e30a3fa8',
|
||||
'phabricator-remarkup-css' => '023adc14',
|
||||
'phabricator-shaped-request' => '310cd201',
|
||||
'phabricator-side-menu-view-css' => '023adc14',
|
||||
'phabricator-standard-page-view' => '023adc14',
|
||||
'phabricator-textareautils' => '66dca903',
|
||||
'phabricator-tooltip' => '66dca903',
|
||||
'phabricator-textareautils' => 'b3c1b6e7',
|
||||
'phabricator-tooltip' => 'b3c1b6e7',
|
||||
'phabricator-transaction-view-css' => '023adc14',
|
||||
'phabricator-zindex-css' => '023adc14',
|
||||
'sprite-apps-large-css' => '023adc14',
|
||||
|
|
|
@ -218,6 +218,7 @@ phutil_register_library_map(array(
|
|||
'ConpherenceViewController' => 'applications/conpherence/controller/ConpherenceViewController.php',
|
||||
'DarkConsoleController' => 'aphront/console/DarkConsoleController.php',
|
||||
'DarkConsoleCore' => 'aphront/console/DarkConsoleCore.php',
|
||||
'DarkConsoleDataController' => 'aphront/console/DarkConsoleDataController.php',
|
||||
'DarkConsoleErrorLogPlugin' => 'aphront/console/plugin/DarkConsoleErrorLogPlugin.php',
|
||||
'DarkConsoleErrorLogPluginAPI' => 'aphront/console/plugin/errorlog/DarkConsoleErrorLogPluginAPI.php',
|
||||
'DarkConsoleEventPlugin' => 'aphront/console/plugin/DarkConsoleEventPlugin.php',
|
||||
|
@ -1693,6 +1694,7 @@ phutil_register_library_map(array(
|
|||
'ConpherenceUpdateController' => 'ConpherenceController',
|
||||
'ConpherenceViewController' => 'ConpherenceController',
|
||||
'DarkConsoleController' => 'PhabricatorController',
|
||||
'DarkConsoleDataController' => 'PhabricatorController',
|
||||
'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin',
|
||||
'DarkConsoleEventPlugin' => 'DarkConsolePlugin',
|
||||
'DarkConsoleEventPluginAPI' => 'PhutilEventListener',
|
||||
|
|
|
@ -73,7 +73,10 @@ class AphrontDefaultApplicationConfiguration
|
|||
'profile/(?P<phid>[^/]+)/' => 'PhabricatorXHProfProfileController',
|
||||
),
|
||||
|
||||
'/~/' => 'DarkConsoleController',
|
||||
'/~/' => array(
|
||||
'' => 'DarkConsoleController',
|
||||
'data/(?P<key>[^/]+)/' => 'DarkConsoleDataController',
|
||||
),
|
||||
|
||||
'/search/' => array(
|
||||
'' => 'PhabricatorSearchController',
|
||||
|
|
|
@ -5,57 +5,32 @@
|
|||
*/
|
||||
final class DarkConsoleCore {
|
||||
|
||||
const PLUGIN_ERRORLOG = 'ErrorLog';
|
||||
const PLUGIN_SERVICES = 'Services';
|
||||
const PLUGIN_EVENT = 'Event';
|
||||
const PLUGIN_XHPROF = 'XHProf';
|
||||
const PLUGIN_REQUEST = 'Request';
|
||||
|
||||
public static function getPlugins() {
|
||||
return array(
|
||||
self::PLUGIN_ERRORLOG,
|
||||
self::PLUGIN_REQUEST,
|
||||
self::PLUGIN_SERVICES,
|
||||
self::PLUGIN_EVENT,
|
||||
self::PLUGIN_XHPROF,
|
||||
);
|
||||
}
|
||||
|
||||
private $plugins = array();
|
||||
private $settings;
|
||||
private $coredata;
|
||||
|
||||
public function getPlugin($plugin_name) {
|
||||
return idx($this->plugins, $plugin_name);
|
||||
}
|
||||
const STORAGE_VERSION = 1;
|
||||
|
||||
public function __construct() {
|
||||
foreach (self::getPlugins() as $plugin_name) {
|
||||
$plugin = self::newPlugin($plugin_name);
|
||||
if ($plugin->isPermanent() || !isset($disabled[$plugin_name])) {
|
||||
if ($plugin->shouldStartup()) {
|
||||
$plugin->didStartup();
|
||||
$plugin->setConsoleCore($this);
|
||||
$this->plugins[$plugin_name] = $plugin;
|
||||
}
|
||||
$symbols = id(new PhutilSymbolLoader())
|
||||
->setType('class')
|
||||
->setAncestorClass('DarkConsolePlugin')
|
||||
->selectAndLoadSymbols();
|
||||
|
||||
foreach ($symbols as $symbol) {
|
||||
$plugin = newv($symbol['name'], array());
|
||||
if (!$plugin->shouldStartup()) {
|
||||
continue;
|
||||
}
|
||||
$plugin->setConsoleCore($this);
|
||||
$plugin->didStartup();
|
||||
$this->plugins[$symbol['name']] = $plugin;
|
||||
}
|
||||
}
|
||||
|
||||
public static function newPlugin($plugin) {
|
||||
$class = 'DarkConsole'.$plugin.'Plugin';
|
||||
return newv($class, array());
|
||||
}
|
||||
|
||||
public function getEnabledPlugins() {
|
||||
public function getPlugins() {
|
||||
return $this->plugins;
|
||||
}
|
||||
|
||||
public function render(AphrontRequest $request) {
|
||||
|
||||
$user = $request->getUser();
|
||||
|
||||
$plugins = $this->getEnabledPlugins();
|
||||
public function getKey(AphrontRequest $request) {
|
||||
$plugins = $this->getPlugins();
|
||||
|
||||
foreach ($plugins as $plugin) {
|
||||
$plugin->setRequest($request);
|
||||
|
@ -70,128 +45,58 @@ final class DarkConsoleCore {
|
|||
$plugin->setData($plugin->generateData());
|
||||
}
|
||||
|
||||
$selected = $user->getConsoleTab();
|
||||
$visible = $user->getConsoleVisible();
|
||||
$plugins = msort($plugins, 'getOrderKey');
|
||||
|
||||
if (!isset($plugins[$selected])) {
|
||||
$selected = head_key($plugins);
|
||||
}
|
||||
$key = Filesystem::readRandomCharacters(24);
|
||||
|
||||
$tabs = array();
|
||||
foreach ($plugins as $key => $plugin) {
|
||||
$tabs[$key] = array(
|
||||
$data = array();
|
||||
foreach ($plugins as $plugin) {
|
||||
$class = get_class($plugin);
|
||||
$tabs[] = array(
|
||||
'class' => $class,
|
||||
'name' => $plugin->getName(),
|
||||
'panel' => $plugin->render(),
|
||||
'color' => $plugin->getColor(),
|
||||
);
|
||||
$data[$class] = $plugin->getData();
|
||||
}
|
||||
|
||||
$tabs_markup = array();
|
||||
$panel_markup = array();
|
||||
foreach ($tabs as $key => $data) {
|
||||
$is_selected = ($key == $selected);
|
||||
if ($is_selected) {
|
||||
$style = null;
|
||||
$tabclass = 'dark-console-tab-selected';
|
||||
} else {
|
||||
$style = 'display: none;';
|
||||
$tabclass = null;
|
||||
}
|
||||
$storage = array(
|
||||
'vers' => self::STORAGE_VERSION,
|
||||
'tabs' => $tabs,
|
||||
'data' => $data,
|
||||
'user' => $request->getUser()
|
||||
? $request->getUser()->getPHID()
|
||||
: null,
|
||||
);
|
||||
|
||||
$tabs_markup[] = javelin_tag(
|
||||
'a',
|
||||
array(
|
||||
'class' => "dark-console-tab {$tabclass}",
|
||||
'sigil' => 'dark-console-tab',
|
||||
'id' => 'dark-console-tab-'.$key,
|
||||
),
|
||||
(string)$data['name']);
|
||||
$cache = new PhabricatorKeyValueDatabaseCache();
|
||||
$cache = new PhutilKeyValueCacheProfiler($cache);
|
||||
$cache->setProfiler(PhutilServiceProfiler::getInstance());
|
||||
|
||||
$panel_markup[] = javelin_render_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'dark-console-panel dark-console-panel-'.$key,
|
||||
'style' => $style,
|
||||
'sigil' => 'dark-console-panel',
|
||||
),
|
||||
(string)$data['panel']);
|
||||
}
|
||||
|
||||
$console = javelin_render_tag(
|
||||
'table',
|
||||
$cache->setKeys(
|
||||
array(
|
||||
'class' => 'dark-console',
|
||||
'sigil' => 'dark-console',
|
||||
'style' => $visible ? '' : 'display: none;',
|
||||
'darkconsole:'.$key => json_encode($storage),
|
||||
),
|
||||
'<tr>'.
|
||||
'<th class="dark-console-tabs">'.
|
||||
implode("\n", $tabs_markup).
|
||||
'</th>'.
|
||||
'<td>'.implode("\n", $panel_markup).'</td>'.
|
||||
'</tr>');
|
||||
$ttl = (60 * 60 * 6));
|
||||
|
||||
if (!empty($_COOKIE['phsid'])) {
|
||||
$console = str_replace(
|
||||
$_COOKIE['phsid'],
|
||||
phutil_escape_html('<session-key>'),
|
||||
$console);
|
||||
}
|
||||
|
||||
if ($request->isAjax()) {
|
||||
|
||||
// for ajax this HTML gets updated on the client
|
||||
$request_history = null;
|
||||
|
||||
} else {
|
||||
|
||||
$request_table_header =
|
||||
'<div class="dark-console-panel-request-log-separator"></div>';
|
||||
|
||||
$rows = array();
|
||||
|
||||
$table = new AphrontTableView($rows);
|
||||
$table->setHeaders(
|
||||
array(
|
||||
'Sequence',
|
||||
'Type',
|
||||
'URI',
|
||||
));
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
'',
|
||||
'',
|
||||
'wide',
|
||||
));
|
||||
|
||||
$request_table = $request_table_header . $table->render();
|
||||
$request_history = javelin_render_tag(
|
||||
'table',
|
||||
array(
|
||||
'class' => 'dark-console dark-console-request-log',
|
||||
'sigil' => 'dark-console-request-log',
|
||||
'style' => $visible ? '' : 'display: none;',
|
||||
),
|
||||
'<tr>'.
|
||||
'<th class="dark-console-tabs">'.
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'class' => 'dark-console-tab dark-console-tab-selected',
|
||||
),
|
||||
'Request Log').
|
||||
'</th>'.
|
||||
'<td>'.
|
||||
javelin_render_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'dark-console-panel dark-console-panel-RequestLog',
|
||||
),
|
||||
$request_table).
|
||||
'</td>'.
|
||||
'</tr>');
|
||||
}
|
||||
|
||||
return "\n\n\n\n".$console.$request_history."\n\n\n\n";
|
||||
return $key;
|
||||
}
|
||||
|
||||
public function render(AphrontRequest $request) {
|
||||
$user = $request->getUser();
|
||||
$visible = $user ? $user->getConsoleVisible() : true;
|
||||
|
||||
return javelin_tag(
|
||||
'div',
|
||||
array(
|
||||
'id' => 'darkconsole',
|
||||
'class' => 'dark-console',
|
||||
'style' => $visible ? '' : 'display: none;',
|
||||
'data-console-key' => $this->getKey($request),
|
||||
),
|
||||
'');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
69
src/aphront/console/DarkConsoleDataController.php
Normal file
69
src/aphront/console/DarkConsoleDataController.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group console
|
||||
*/
|
||||
final class DarkConsoleDataController extends PhabricatorController {
|
||||
|
||||
private $key;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->key = $data['key'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$cache = new PhabricatorKeyValueDatabaseCache();
|
||||
$cache = new PhutilKeyValueCacheProfiler($cache);
|
||||
$cache->setProfiler(PhutilServiceProfiler::getInstance());
|
||||
|
||||
$result = $cache->getKey('darkconsole:'.$this->key);
|
||||
if (!$result) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
$result = json_decode($result, true);
|
||||
|
||||
if (!is_array($result)) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
if ($result['vers'] != DarkConsoleCore::STORAGE_VERSION) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
if ($result['user'] != $user->getPHID()) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
$output = array();
|
||||
$output['tabs'] = $result['tabs'];
|
||||
$output['panel'] = array();
|
||||
|
||||
foreach ($result['data'] as $class => $data) {
|
||||
try {
|
||||
$obj = newv($class, array());
|
||||
$obj->setData($data);
|
||||
$obj->setRequest($request);
|
||||
|
||||
$panel = $obj->renderPanel();
|
||||
|
||||
if (!empty($_COOKIE['phsid'])) {
|
||||
$panel = str_replace(
|
||||
$_COOKIE['phsid'],
|
||||
'(session-key)',
|
||||
$panel);
|
||||
}
|
||||
|
||||
$output['panel'][$class] = $panel;
|
||||
} catch (Exception $ex) {
|
||||
$output['panel'][$class] = 'error';
|
||||
}
|
||||
}
|
||||
|
||||
return id(new AphrontAjaxResponse())->setContent($output);
|
||||
}
|
||||
|
||||
}
|
|
@ -7,29 +7,32 @@ final class DarkConsoleErrorLogPlugin extends DarkConsolePlugin {
|
|||
|
||||
public function getName() {
|
||||
$count = count($this->getData());
|
||||
|
||||
if ($count) {
|
||||
return
|
||||
'<span style="color: #ff0000;">•</span> '.
|
||||
"Error Log ({$count})";
|
||||
return pht('Error Log (%d)', $count);
|
||||
}
|
||||
|
||||
return 'Error Log';
|
||||
return pht('Error Log');
|
||||
}
|
||||
|
||||
public function getOrder() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getColor() {
|
||||
if (count($this->getData())) {
|
||||
return '#ff0000';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getDescription() {
|
||||
return 'Shows errors and warnings.';
|
||||
return pht('Shows errors and warnings.');
|
||||
}
|
||||
|
||||
|
||||
public function generateData() {
|
||||
return DarkConsoleErrorLogPluginAPI::getErrors();
|
||||
}
|
||||
|
||||
|
||||
public function render() {
|
||||
|
||||
public function renderPanel() {
|
||||
$data = $this->getData();
|
||||
|
||||
$rows = array();
|
||||
|
|
|
@ -37,7 +37,7 @@ final class DarkConsoleEventPlugin extends DarkConsolePlugin {
|
|||
);
|
||||
}
|
||||
|
||||
public function render() {
|
||||
public function renderPanel() {
|
||||
$data = $this->getData();
|
||||
|
||||
$out = array();
|
||||
|
|
|
@ -11,12 +11,27 @@ abstract class DarkConsolePlugin {
|
|||
|
||||
abstract public function getName();
|
||||
abstract public function getDescription();
|
||||
abstract public function render();
|
||||
abstract public function renderPanel();
|
||||
|
||||
public function __construct() {
|
||||
|
||||
}
|
||||
|
||||
public function getColor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
final public function getOrderKey() {
|
||||
return sprintf(
|
||||
'%09d%s',
|
||||
(int)(999999999 * $this->getOrder()),
|
||||
$this->getName());
|
||||
}
|
||||
|
||||
public function getOrder() {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
public function setConsoleCore(DarkConsoleCore $core) {
|
||||
$this->core = $core;
|
||||
return $this;
|
||||
|
@ -52,10 +67,6 @@ abstract class DarkConsolePlugin {
|
|||
return $this->getRequest()->getRequestURI();
|
||||
}
|
||||
|
||||
public function isPermanent() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function shouldStartup() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -20,8 +20,7 @@ final class DarkConsoleRequestPlugin extends DarkConsolePlugin {
|
|||
);
|
||||
}
|
||||
|
||||
public function render() {
|
||||
|
||||
public function renderPanel() {
|
||||
$data = $this->getData();
|
||||
|
||||
$sections = array(
|
||||
|
|
|
@ -136,11 +136,16 @@ final class DarkConsoleServicesPlugin extends DarkConsolePlugin {
|
|||
'start' => PhabricatorStartup::getStartTime(),
|
||||
'end' => microtime(true),
|
||||
'log' => $log,
|
||||
'analyzeURI' => (string)$this
|
||||
->getRequestURI()
|
||||
->alter('__analyze__', true),
|
||||
'didAnalyze' => isset($_REQUEST['__analyze__']),
|
||||
);
|
||||
}
|
||||
|
||||
public function render() {
|
||||
public function renderPanel() {
|
||||
$data = $this->getData();
|
||||
|
||||
$log = $data['log'];
|
||||
$results = array();
|
||||
|
||||
|
@ -149,8 +154,8 @@ final class DarkConsoleServicesPlugin extends DarkConsolePlugin {
|
|||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $this->getRequestURI()->alter('__analyze__', true),
|
||||
'class' => isset($_REQUEST['__analyze__'])
|
||||
'href' => $data['analyzeURI'],
|
||||
'class' => $data['didAnalyze']
|
||||
? 'disabled button'
|
||||
: 'green button',
|
||||
),
|
||||
|
|
|
@ -8,28 +8,40 @@ final class DarkConsoleXHProfPlugin extends DarkConsolePlugin {
|
|||
protected $xhprofID;
|
||||
|
||||
public function getName() {
|
||||
$run = $this->getData();
|
||||
|
||||
if ($run) {
|
||||
return '<span style="color: #ff00ff;">•</span> XHProf';
|
||||
}
|
||||
|
||||
return 'XHProf';
|
||||
}
|
||||
|
||||
public function getColor() {
|
||||
$data = $this->getData();
|
||||
if ($data['xhprofID']) {
|
||||
return '#ff00ff';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getDescription() {
|
||||
return 'Provides detailed PHP profiling information through XHProf.';
|
||||
}
|
||||
|
||||
public function generateData() {
|
||||
return $this->xhprofID;
|
||||
return array(
|
||||
'xhprofID' => $this->xhprofID,
|
||||
'profileURI' => (string)$this
|
||||
->getRequestURI()
|
||||
->alter('__profile__', 'page'),
|
||||
);
|
||||
}
|
||||
|
||||
public function getXHProfRunID() {
|
||||
return $this->xhprofID;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
public function renderPanel() {
|
||||
$data = $this->getData();
|
||||
|
||||
$run = $data['xhprofID'];
|
||||
$profile_uri = $data['profileURI'];
|
||||
|
||||
if (!DarkConsoleXHProfPluginAPI::isProfilerAvailable()) {
|
||||
$href = PhabricatorEnv::getDoclink('article/Installation_Guide.html');
|
||||
$install_guide = phutil_tag(
|
||||
|
@ -49,14 +61,12 @@ final class DarkConsoleXHProfPlugin extends DarkConsolePlugin {
|
|||
|
||||
$result = array();
|
||||
|
||||
$run = $this->getXHProfRunID();
|
||||
|
||||
$header =
|
||||
'<div class="dark-console-panel-header">'.
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $this->getRequestURI()->alter('__profile__', 'page'),
|
||||
'href' => $profile_uri,
|
||||
'class' => $run
|
||||
? 'disabled button'
|
||||
: 'green button',
|
||||
|
|
|
@ -38,10 +38,10 @@ final class AphrontAjaxResponse extends AphrontResponse {
|
|||
$console = $this->getConsole();
|
||||
if ($console) {
|
||||
Javelin::initBehavior(
|
||||
'dark-console-ajax',
|
||||
'dark-console',
|
||||
array(
|
||||
'console' => $console->render($this->getRequest()),
|
||||
'uri' => (string) $this->getRequest()->getRequestURI(),
|
||||
'uri' => (string)$this->getRequest()->getRequestURI(),
|
||||
'key' => $console->getKey($this->getRequest()),
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -164,8 +164,9 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
|||
Javelin::initBehavior(
|
||||
'dark-console',
|
||||
array(
|
||||
'uri' => '/~/',
|
||||
'request_uri' => $request ? (string) $request->getRequestURI() : '/',
|
||||
'uri' => $request ? (string)$request->getRequestURI() : '?',
|
||||
'selected' => $user ? $user->getConsoleTab() : null,
|
||||
'visible' => $user ? (int)$user->getConsoleVisible() : true,
|
||||
));
|
||||
|
||||
// Change this to initBehavior when there is some behavior to initialize
|
||||
|
@ -225,13 +226,15 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
|||
}
|
||||
|
||||
protected function willSendResponse($response) {
|
||||
$request = $this->getRequest();
|
||||
$response = parent::willSendResponse($response);
|
||||
|
||||
$console = $this->getRequest()->getApplicationConfiguration()->getConsole();
|
||||
$console = $request->getApplicationConfiguration()->getConsole();
|
||||
|
||||
if ($console) {
|
||||
$response = str_replace(
|
||||
'<darkconsole />',
|
||||
$console->render($this->getRequest()),
|
||||
$console->render($request),
|
||||
$response);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
|
||||
.dark-console {
|
||||
background: #555555;
|
||||
background: #444444;
|
||||
color: #eeeeee;
|
||||
width: 100%;
|
||||
font-family: "Verdana";
|
||||
|
@ -11,54 +11,101 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.dark-console a:link {
|
||||
color: inherit;
|
||||
.dark-console-requests,
|
||||
.dark-console-tabs {
|
||||
position: absolute;
|
||||
overflow-y: auto;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 15%;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.dark-console-requests,
|
||||
.dark-console-tabs,
|
||||
.dark-console-panel,
|
||||
.dark-console-load {
|
||||
border-left: 1px solid #111111;
|
||||
box-shadow: -2px 0px 2px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.dark-console-requests {
|
||||
background: #222222;
|
||||
}
|
||||
|
||||
.dark-console-tabs {
|
||||
width: 180px;
|
||||
background: #222222;
|
||||
border-right: 1px solid #888888;
|
||||
padding: 2.5em 0em;
|
||||
background: #333333;
|
||||
left: 15%;
|
||||
}
|
||||
|
||||
.dark-console-panel,
|
||||
.dark-console-load {
|
||||
position: relative;
|
||||
min-height: 320px;
|
||||
}
|
||||
|
||||
a.dark-console-tab {
|
||||
padding: .75em 12px;
|
||||
text-align: right;
|
||||
background: #444444;
|
||||
position: relative;
|
||||
border: 1px solid #666666;
|
||||
.dark-console-panel {
|
||||
margin-left: 30%;
|
||||
background: #444444;
|
||||
}
|
||||
|
||||
.dark-console-requests a.dark-console-request,
|
||||
.dark-console-tabs a.dark-console-tab {
|
||||
display: block;
|
||||
padding: 6px;
|
||||
overflow: hidden;
|
||||
background: #444444;
|
||||
margin: 3px 0;
|
||||
color: #cccccc;
|
||||
border-color: #666666;
|
||||
border-width: 1px 0;
|
||||
border-right-color: #888888;
|
||||
margin-bottom: 2px;
|
||||
display: block;
|
||||
color: #cccccc;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
a.dark-console-tab-selected {
|
||||
margin-right: -1px;
|
||||
padding-right: 13px;
|
||||
background: #555555;
|
||||
border-color: #888888;
|
||||
border-right-color: #555555;
|
||||
color: #eeeeee;
|
||||
.dark-console-requests a.dark-selected,
|
||||
.dark-console-tabs a.dark-selected {
|
||||
background: #0066aa;
|
||||
}
|
||||
|
||||
.dark-console-requests a.dark-console-request:hover,
|
||||
.dark-console-tabs a.dark-console-tab:hover {
|
||||
background: #1188cc;
|
||||
}
|
||||
|
||||
.dark-console-tabs a.dark-console-tab {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.dark-console-load {
|
||||
background-image: url(/rsrc/image/darkload.gif);
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-color: #000;
|
||||
margin-left: 15%;
|
||||
}
|
||||
|
||||
.dark-console .aphront-table-view {
|
||||
font-size: 11px;
|
||||
background: #888888;
|
||||
color: #eeeeee;
|
||||
margin: 1em 1%;
|
||||
width: 98%;
|
||||
width: 100%;
|
||||
border-color: #333333;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.dark-console .aphront-table-view th {
|
||||
text-shadow: none;
|
||||
font-family: "Verdana";
|
||||
font-size: 11px;
|
||||
background: #333333;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.dark-console .aphront-table-view td {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.dark-console .aphront-table-view td.header {
|
||||
background: #444444;
|
||||
color: #ffffff;
|
||||
|
@ -77,13 +124,8 @@ a.dark-console-tab-selected {
|
|||
color: #dddddd;
|
||||
}
|
||||
|
||||
.dark-console-panel-ErrorLog {
|
||||
max-height: 500px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.dark-console-panel-error-details {
|
||||
display: none;
|
||||
.dark-console-panel-core {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.explain-sev-1 {
|
||||
|
@ -119,15 +161,11 @@ a.dark-console-tab-selected {
|
|||
}
|
||||
|
||||
.dark-console-panel-header {
|
||||
background: #606060;
|
||||
border-bottom: 1px solid #505050;
|
||||
padding: .25em 1em .25em 0;
|
||||
padding: 8px 4px 0;
|
||||
}
|
||||
|
||||
.dark-console-panel-header h1 {
|
||||
padding: 1em;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.dark-console-panel-header .button {
|
||||
|
@ -168,4 +206,11 @@ a.dark-console-tab-selected {
|
|||
height: 2px;
|
||||
}
|
||||
|
||||
.dark-console-panel-ErrorLog {
|
||||
max-height: 500px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.dark-console-panel-error-details {
|
||||
display: none;
|
||||
}
|
||||
|
|
BIN
webroot/rsrc/image/darkload.gif
Normal file
BIN
webroot/rsrc/image/darkload.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.2 KiB |
|
@ -1,49 +0,0 @@
|
|||
/**
|
||||
* @provides javelin-behavior-dark-console-ajax
|
||||
* @requires javelin-behavior
|
||||
* javelin-dom
|
||||
*/
|
||||
|
||||
JX.behavior('dark-console-ajax', function(config) {
|
||||
var requestLog = JX.DOM.find(document.body,
|
||||
'table',
|
||||
'dark-console-request-log');
|
||||
var requestTable = JX.DOM.find(requestLog, 'table');
|
||||
var requestRows = JX.DOM.scry(requestTable, 'tr');
|
||||
var requestNumber = requestRows.length - 1; // header don't count
|
||||
var requestURI = config.uri;
|
||||
var console = JX.$H(config.console);
|
||||
var newRowType = 'ajax';
|
||||
|
||||
var newRowNumber = JX.$N(
|
||||
'a',
|
||||
{
|
||||
'sigil' : 'request-log-number',
|
||||
'meta' : { 'console' : console }
|
||||
},
|
||||
requestNumber
|
||||
);
|
||||
var newRowURI = JX.$N(
|
||||
'a',
|
||||
{
|
||||
'sigil' : 'request-log-uri',
|
||||
'meta' : { 'console' : console }
|
||||
},
|
||||
requestURI
|
||||
);
|
||||
|
||||
var newRow = JX.$N(
|
||||
'tr',
|
||||
{
|
||||
'className' : requestNumber % 2 ? 'alt' : ''
|
||||
},
|
||||
[
|
||||
JX.$N('td', {}, newRowNumber),
|
||||
JX.$N('td', {}, newRowType),
|
||||
JX.$N('td', {}, newRowURI)
|
||||
]
|
||||
);
|
||||
|
||||
JX.DOM.appendContent(requestTable, newRow);
|
||||
|
||||
});
|
|
@ -6,55 +6,221 @@
|
|||
* javelin-dom
|
||||
* javelin-request
|
||||
* phabricator-keyboard-shortcut
|
||||
* javelin-behavior-dark-console-ajax
|
||||
*/
|
||||
|
||||
JX.behavior('dark-console', function(config) {
|
||||
var selected_tab = null;
|
||||
JX.behavior('dark-console', function(config, statics) {
|
||||
var root = statics.root || setup_console();
|
||||
|
||||
JX.Stratcom.listen(
|
||||
'click',
|
||||
['dark-console', 'dark-console-tab'],
|
||||
function(e) {
|
||||
var console = e.getNode('dark-console');
|
||||
var tabs = JX.DOM.scry(console, 'a', 'dark-console-tab');
|
||||
var panels = JX.DOM.scry(console, 'div', 'dark-console-panel');
|
||||
var target = e.getTarget();
|
||||
for (var ii = 0; ii < tabs.length; ii++) {
|
||||
JX.DOM.alterClass(
|
||||
tabs[ii],
|
||||
'dark-console-tab-selected',
|
||||
tabs[ii] == target);
|
||||
(tabs[ii] != target ? JX.DOM.hide : JX.DOM.show)(panels[ii]);
|
||||
config.key = config.key || root.getAttribute('data-console-key');
|
||||
add_request(config);
|
||||
|
||||
|
||||
// Do first-time setup.
|
||||
function setup_console() {
|
||||
statics.root = JX.$('darkconsole');
|
||||
statics.req = {all: {}, current: null};
|
||||
statics.tab = {all: {}, current: null};
|
||||
|
||||
statics.el = {};
|
||||
|
||||
statics.el.reqs = JX.$N('div', {className: 'dark-console-requests'});
|
||||
statics.root.appendChild(statics.el.reqs);
|
||||
|
||||
statics.el.tabs = JX.$N('div', {className: 'dark-console-tabs'});
|
||||
statics.root.appendChild(statics.el.tabs);
|
||||
|
||||
statics.el.panel = JX.$N('div', {className: 'dark-console-panel'});
|
||||
statics.root.appendChild(statics.el.panel);
|
||||
|
||||
statics.el.load = JX.$N('div', {className: 'dark-console-load'});
|
||||
statics.root.appendChild(statics.el.load);
|
||||
|
||||
statics.cache = {};
|
||||
|
||||
statics.visible = config.visible;
|
||||
statics.selected = config.selected;
|
||||
|
||||
return statics.root;
|
||||
}
|
||||
|
||||
|
||||
// Add a new request to the console (initial page load, or new Ajax response).
|
||||
function add_request(config) {
|
||||
|
||||
// Ignore DarkConsole data requests.
|
||||
if (config.uri.match(new RegExp('^/~/data/'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
var attr = {
|
||||
className: 'dark-console-request',
|
||||
sigil: 'dark-console-request',
|
||||
title: config.uri,
|
||||
meta: config,
|
||||
href: '#'
|
||||
};
|
||||
|
||||
var link = JX.$N('a', attr, config.uri);
|
||||
statics.el.reqs.appendChild(link);
|
||||
statics.req.all[config.key] = link;
|
||||
|
||||
if (!statics.req.current) {
|
||||
select_request(config.key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Select a request (on load, or when the user clicks one).
|
||||
function select_request(key) {
|
||||
var req = statics.req;
|
||||
|
||||
if (req.current) {
|
||||
JX.DOM.alterClass(req.all[req.current], 'dark-selected', false);
|
||||
}
|
||||
statics.req.current = key;
|
||||
JX.DOM.alterClass(req.all[req.current], 'dark-selected', true);
|
||||
|
||||
if (statics.visible) {
|
||||
JX.log('visible!');
|
||||
draw_request(key);
|
||||
}
|
||||
}
|
||||
|
||||
// When the user clicks a request, select it.
|
||||
JX.Stratcom.listen('click', 'dark-console-request', function(e) {
|
||||
e.kill();
|
||||
select_request(e.getNodeData('dark-console-request').key);
|
||||
});
|
||||
|
||||
|
||||
// After the user selects a request, draw its tabs.
|
||||
function draw_request(key) {
|
||||
var cache = statics.cache;
|
||||
|
||||
if (cache[key]) {
|
||||
render_request(key);
|
||||
return;
|
||||
}
|
||||
|
||||
new JX.Request(
|
||||
'/~/data/' + key + '/',
|
||||
function(r) {
|
||||
cache[key] = r;
|
||||
if (statics.req.current == key) {
|
||||
render_request(key);
|
||||
}
|
||||
})
|
||||
.send();
|
||||
|
||||
show_loading();
|
||||
}
|
||||
|
||||
// Show the loading indicator.
|
||||
function show_loading() {
|
||||
JX.DOM.hide(statics.el.tabs);
|
||||
JX.DOM.hide(statics.el.panel);
|
||||
JX.DOM.show(statics.el.load);
|
||||
}
|
||||
|
||||
// Hide the loading indicator.
|
||||
function hide_loading() {
|
||||
JX.DOM.show(statics.el.tabs);
|
||||
JX.DOM.show(statics.el.panel);
|
||||
JX.DOM.hide(statics.el.load);
|
||||
}
|
||||
|
||||
function render_request(key) {
|
||||
var data = statics.cache[key];
|
||||
|
||||
statics.tab.all = {};
|
||||
|
||||
var links = [];
|
||||
var first = null;
|
||||
for (var ii = 0; ii < data.tabs.length; ii++) {
|
||||
var tab = data.tabs[ii];
|
||||
var attr = {
|
||||
className: 'dark-console-tab',
|
||||
sigil: 'dark-console-tab',
|
||||
meta: tab,
|
||||
href: '#'
|
||||
};
|
||||
|
||||
var bullet = null;
|
||||
if (tab.color) {
|
||||
bullet = JX.$N('span', {style: {color: tab.color}}, "\u2022");
|
||||
}
|
||||
|
||||
selected_tab = target.id.replace('dark-console-tab-', '');
|
||||
var link = JX.$N('a', attr, [bullet, ' ', tab.name]);
|
||||
links.push(link);
|
||||
statics.tab.all[tab['class']] = link;
|
||||
first = first || tab['class'];
|
||||
}
|
||||
|
||||
new JX.Request(config.uri, JX.bag)
|
||||
.setData({ tab : selected_tab })
|
||||
JX.DOM.setContent(statics.el.tabs, links);
|
||||
|
||||
if (statics.tab.current in statics.tab.all) {
|
||||
select_tab(statics.tab.current);
|
||||
} else if (statics.selected in statics.tab.all) {
|
||||
select_tab(statics.selected);
|
||||
} else {
|
||||
select_tab(first);
|
||||
}
|
||||
|
||||
hide_loading();
|
||||
}
|
||||
|
||||
function select_tab(tclass) {
|
||||
var tabs = statics.tab;
|
||||
|
||||
if (tabs.current) {
|
||||
JX.DOM.alterClass(tabs.current, 'dark-selected', false);
|
||||
}
|
||||
tabs.current = tabs.all[tclass];
|
||||
JX.DOM.alterClass(tabs.current, 'dark-selected', true);
|
||||
|
||||
if (tclass != statics.selected) {
|
||||
// Save user preference.
|
||||
new JX.Request('/~/', JX.bag)
|
||||
.setData({ tab : tclass })
|
||||
.send();
|
||||
});
|
||||
}
|
||||
|
||||
draw_panel();
|
||||
}
|
||||
|
||||
// When the user clicks a tab, select it.
|
||||
JX.Stratcom.listen('click', 'dark-console-tab', function(e) {
|
||||
e.kill();
|
||||
select_tab(e.getNodeData('dark-console-tab')['class']);
|
||||
});
|
||||
|
||||
function draw_panel() {
|
||||
var data = statics.cache[statics.req.current];
|
||||
var tclass = JX.Stratcom.getData(statics.tab.current)['class'];
|
||||
var html = data.panel[tclass];
|
||||
|
||||
var div = JX.$N('div', {className: 'dark-console-panel-core'}, JX.$H(html));
|
||||
JX.DOM.setContent(statics.el.panel, div);
|
||||
}
|
||||
|
||||
// Install keyboard shortcut.
|
||||
var desc = 'Toggle visibility of DarkConsole.';
|
||||
new JX.KeyboardShortcut('`', desc)
|
||||
.setHandler(function(manager) {
|
||||
var console = JX.DOM.find(document.body, 'table', 'dark-console');
|
||||
var requestLog = JX.DOM.find(
|
||||
document.body,
|
||||
'table',
|
||||
'dark-console-request-log');
|
||||
statics.visible = !statics.visible;
|
||||
|
||||
config.visible = !config.visible;
|
||||
if (config.visible) {
|
||||
JX.DOM.show(console);
|
||||
JX.DOM.show(requestLog);
|
||||
if (statics.visible) {
|
||||
JX.DOM.show(root);
|
||||
if (statics.req.current) {
|
||||
draw_request(statics.req.current);
|
||||
}
|
||||
} else {
|
||||
JX.DOM.hide(console);
|
||||
JX.DOM.hide(requestLog);
|
||||
JX.DOM.hide(root);
|
||||
}
|
||||
|
||||
new JX.Request(config.uri, JX.bag)
|
||||
.setData({visible: config.visible ? 1 : 0})
|
||||
// Save user preference.
|
||||
new JX.Request('/~/', JX.bag)
|
||||
.setData({visible: statics.visible ? 1 : 0})
|
||||
.send();
|
||||
|
||||
// Force resize listeners to take effect.
|
||||
|
@ -62,89 +228,4 @@ JX.behavior('dark-console', function(config) {
|
|||
})
|
||||
.register();
|
||||
|
||||
var initRequestLog = function() {
|
||||
var console = JX.DOM.find(document.body,
|
||||
'table',
|
||||
'dark-console');
|
||||
var requestLog = JX.DOM.find(document.body,
|
||||
'table',
|
||||
'dark-console-request-log');
|
||||
var requestTable = JX.DOM.find(requestLog, 'table');
|
||||
var rows = JX.DOM.scry(requestTable, 'tr');
|
||||
var tableHeader = rows[0];
|
||||
var newRowNumber = JX.$N(
|
||||
'a',
|
||||
{
|
||||
'sigil' : 'request-log-number',
|
||||
'meta' : { 'console' : console }
|
||||
},
|
||||
"0"
|
||||
);
|
||||
var newRowURI = JX.$N(
|
||||
'a',
|
||||
{
|
||||
'sigil' : 'request-log-uri',
|
||||
'meta' : { 'console' : console }
|
||||
},
|
||||
config.request_uri
|
||||
);
|
||||
|
||||
var newRow = JX.$N(
|
||||
'tr',
|
||||
{
|
||||
'className' : 'highlight'
|
||||
},
|
||||
[
|
||||
JX.$N('td', {}, newRowNumber),
|
||||
JX.$N('td', {}, 'main'),
|
||||
JX.$N('td', {}, newRowURI)
|
||||
]
|
||||
);
|
||||
|
||||
JX.DOM.setContent(requestTable, [tableHeader, newRow]);
|
||||
}
|
||||
|
||||
initRequestLog();
|
||||
|
||||
var updateActiveRequest = function(e) {
|
||||
var log = e.getNode('dark-console-request-log');
|
||||
var table = JX.DOM.find(log, 'table');
|
||||
var rows = JX.DOM.scry(table, 'tr');
|
||||
var targetRow = e.getTarget().parentNode.parentNode;
|
||||
var data = JX.Stratcom.getData(e.getTarget());
|
||||
var newConsole = data.console;
|
||||
for (var ii = 0; ii < rows.length; ii++) {
|
||||
JX.DOM.alterClass(
|
||||
rows[ii],
|
||||
'highlight',
|
||||
rows[ii] == targetRow);
|
||||
}
|
||||
var console = JX.DOM.find(document.body, 'table', 'dark-console');
|
||||
JX.DOM.replace(console, newConsole);
|
||||
if (selected_tab) {
|
||||
console = JX.DOM.find(document.body, 'table', 'dark-console');
|
||||
var s_id = 'dark-console-tab-' + selected_tab;
|
||||
var tabs = JX.DOM.scry(console, 'a', 'dark-console-tab');
|
||||
var panels = JX.DOM.scry(console, 'div', 'dark-console-panel');
|
||||
for (var ii = 0; ii < tabs.length; ii++) {
|
||||
JX.DOM.alterClass(
|
||||
tabs[ii],
|
||||
'dark-console-tab-selected',
|
||||
tabs[ii].id == s_id);
|
||||
(tabs[ii].id != s_id ? JX.DOM.hide : JX.DOM.show)(panels[ii]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JX.Stratcom.listen(
|
||||
'click',
|
||||
['dark-console-request-log', 'request-log-number'],
|
||||
updateActiveRequest
|
||||
);
|
||||
JX.Stratcom.listen(
|
||||
'click',
|
||||
['dark-console-request-log', 'request-log-uri'],
|
||||
updateActiveRequest
|
||||
);
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue