Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2890065
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
85 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php
index 48e6ef848e..54800c50f8 100644
--- a/src/__celerity_resource_map__.php
+++ b/src/__celerity_resource_map__.php
@@ -1,1323 +1,1323 @@
<?php
/**
* This file is automatically generated. Use 'celerity_mapper.php' to rebuild
* it.
* @generated
*/
celerity_register_resource_map(array(
'aphront-attached-file-view-css' =>
array(
'uri' => '/res/a6ca5487/rsrc/css/aphront/attached-file-view.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/aphront/attached-file-view.css',
),
'aphront-crumbs-view-css' =>
array(
'uri' => '/res/9009e6bd/rsrc/css/aphront/crumbs-view.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/aphront/crumbs-view.css',
),
'aphront-dark-console-css' =>
array(
- 'uri' => '/res/e7011594/rsrc/css/aphront/dark-console.css',
+ 'uri' => '/res/a7d1dbf1/rsrc/css/aphront/dark-console.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/aphront/dark-console.css',
),
'aphront-dialog-view-css' =>
array(
'uri' => '/res/61a58113/rsrc/css/aphront/dialog-view.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/aphront/dialog-view.css',
),
'aphront-error-view-css' =>
array(
'uri' => '/res/e4c5e4ed/rsrc/css/aphront/error-view.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/aphront/error-view.css',
),
'aphront-form-view-css' =>
array(
'uri' => '/res/8ee16aba/rsrc/css/aphront/form-view.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/aphront/form-view.css',
),
'aphront-headsup-action-list-view-css' =>
array(
'uri' => '/res/af3dff49/rsrc/css/aphront/headsup-action-list-view.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/aphront/headsup-action-list-view.css',
),
'aphront-list-filter-view-css' =>
array(
'uri' => '/res/0f5ddaba/rsrc/css/aphront/list-filter-view.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/aphront/list-filter-view.css',
),
'aphront-pager-view-css' =>
array(
'uri' => '/res/43fb79f0/rsrc/css/aphront/pager-view.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/aphront/pager-view.css',
),
'aphront-panel-view-css' =>
array(
'uri' => '/res/e0139b9c/rsrc/css/aphront/panel-view.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/aphront/panel-view.css',
),
'aphront-request-failure-view-css' =>
array(
'uri' => '/res/c9a43002/rsrc/css/aphront/request-failure-view.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/aphront/request-failure-view.css',
),
'aphront-side-nav-view-css' =>
array(
'uri' => '/res/f92966bd/rsrc/css/aphront/side-nav-view.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/aphront/side-nav-view.css',
),
'aphront-table-view-css' =>
array(
'uri' => '/res/910e83ec/rsrc/css/aphront/table-view.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/aphront/table-view.css',
),
'aphront-tokenizer-control-css' =>
array(
'uri' => '/res/f530af47/rsrc/css/aphront/tokenizer.css',
'type' => 'css',
'requires' =>
array(
0 => 'aphront-typeahead-control-css',
),
'disk' => '/rsrc/css/aphront/tokenizer.css',
),
'aphront-typeahead-control-css' =>
array(
'uri' => '/res/a05236a6/rsrc/css/aphront/typeahead.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/aphront/typeahead.css',
),
'differential-changeset-view-css' =>
array(
'uri' => '/res/d2923406/rsrc/css/application/differential/changeset-view.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/differential/changeset-view.css',
),
'differential-core-view-css' =>
array(
'uri' => '/res/438fe316/rsrc/css/application/differential/core.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/differential/core.css',
),
'differential-inline-comment-editor' =>
array(
'uri' => '/res/5e4f0aa4/rsrc/js/application/differential/DifferentialInlineCommentEditor.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-dom',
1 => 'javelin-workflow',
2 => 'javelin-util',
3 => 'javelin-stratcom',
4 => 'javelin-install',
),
'disk' => '/rsrc/js/application/differential/DifferentialInlineCommentEditor.js',
),
'differential-revision-add-comment-css' =>
array(
'uri' => '/res/849748d3/rsrc/css/application/differential/add-comment.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/differential/add-comment.css',
),
'differential-revision-comment-css' =>
array(
'uri' => '/res/9fb8013b/rsrc/css/application/differential/revision-comment.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/differential/revision-comment.css',
),
'differential-revision-comment-list-css' =>
array(
'uri' => '/res/3b31faa3/rsrc/css/application/differential/revision-comment-list.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/differential/revision-comment-list.css',
),
'differential-revision-detail-css' =>
array(
'uri' => '/res/015e5995/rsrc/css/application/differential/revision-detail.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/differential/revision-detail.css',
),
'differential-revision-history-css' =>
array(
'uri' => '/res/0d7d515d/rsrc/css/application/differential/revision-history.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/differential/revision-history.css',
),
'differential-table-of-contents-css' =>
array(
'uri' => '/res/d173445b/rsrc/css/application/differential/table-of-contents.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/differential/table-of-contents.css',
),
'diffusion-commit-view-css' =>
array(
'uri' => '/res/bc39d876/rsrc/css/application/diffusion/commit-view.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/diffusion/commit-view.css',
),
'diffusion-source-css' =>
array(
'uri' => '/res/db4566b6/rsrc/css/application/diffusion/diffusion-source.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/diffusion/diffusion-source.css',
),
'herald-css' =>
array(
'uri' => '/res/5051f3ab/rsrc/css/application/herald/herald.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/herald/herald.css',
),
'herald-rule-editor' =>
array(
'uri' => '/res/ba957508/rsrc/js/application/herald/HeraldRuleEditor.js',
'type' => 'js',
'requires' =>
array(
0 => 'multirow-row-manager',
1 => 'javelin-install',
2 => 'javelin-typeahead',
3 => 'javelin-util',
4 => 'javelin-dom',
5 => 'javelin-tokenizer',
6 => 'javelin-typeahead-preloaded-source',
7 => 'javelin-stratcom',
8 => 'javelin-json',
),
'disk' => '/rsrc/js/application/herald/HeraldRuleEditor.js',
),
'herald-test-css' =>
array(
'uri' => '/res/c0cd6bdb/rsrc/css/application/herald/herald-test.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/herald/herald-test.css',
),
'javelin-behavior' =>
array(
'uri' => '/res/b28adfa1/rsrc/js/javelin/lib/behavior.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-magical-init',
),
'disk' => '/rsrc/js/javelin/lib/behavior.js',
),
0 =>
array(
'uri' => '/res/1da00bfe/rsrc/js/javelin/lib/__tests__/URI.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-uri',
1 => 'javelin-php-serializer',
),
'disk' => '/rsrc/js/javelin/lib/__tests__/URI.js',
),
'javelin-behavior-aphront-basic-tokenizer' =>
array(
'uri' => '/res/5e183bd5/rsrc/js/application/core/behavior-tokenizer.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-typeahead',
2 => 'javelin-tokenizer',
3 => 'javelin-typeahead-preloaded-source',
4 => 'javelin-dom',
5 => 'javelin-stratcom',
),
'disk' => '/rsrc/js/application/core/behavior-tokenizer.js',
),
'javelin-behavior-aphront-drag-and-drop' =>
array(
'uri' => '/res/170115f4/rsrc/js/application/core/behavior-drag-and-drop.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
2 => 'javelin-util',
3 => 'phabricator-drag-and-drop-file-upload',
),
'disk' => '/rsrc/js/application/core/behavior-drag-and-drop.js',
),
'javelin-behavior-aphront-form-disable-on-submit' =>
array(
'uri' => '/res/6c659ede/rsrc/js/application/core/behavior-form.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-stratcom',
2 => 'javelin-dom',
),
'disk' => '/rsrc/js/application/core/behavior-form.js',
),
'javelin-behavior-countdown-timer' =>
array(
'uri' => '/res/9eef8193/rsrc/js/application/countdown/timer.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
2 => 'javelin-util',
),
'disk' => '/rsrc/js/application/countdown/timer.js',
),
'javelin-behavior-dark-console' =>
array(
'uri' => '/res/c80156c4/rsrc/js/application/core/behavior-dark-console.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-stratcom',
2 => 'javelin-util',
3 => 'javelin-dom',
4 => 'javelin-request',
5 => 'phabricator-keyboard-shortcut',
),
'disk' => '/rsrc/js/application/core/behavior-dark-console.js',
),
'javelin-behavior-differential-accept-with-errors' =>
array(
'uri' => '/res/41c4685b/rsrc/js/application/differential/behavior-accept-with-errors.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
),
'disk' => '/rsrc/js/application/differential/behavior-accept-with-errors.js',
),
'javelin-behavior-differential-add-reviewers-and-ccs' =>
array(
'uri' => '/res/fc352745/rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
2 => 'javelin-tokenizer',
3 => 'javelin-typeahead',
4 => 'javelin-typeahead-preloaded-source',
),
'disk' => '/rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js',
),
'javelin-behavior-differential-comment-jump' =>
array(
'uri' => '/res/be77fced/rsrc/js/application/differential/behavior-comment-jump.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-util',
2 => 'javelin-dom',
),
'disk' => '/rsrc/js/application/differential/behavior-comment-jump.js',
),
'javelin-behavior-differential-diff-radios' =>
array(
'uri' => '/res/004cb66f/rsrc/js/application/differential/behavior-diff-radios.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-stratcom',
2 => 'javelin-dom',
),
'disk' => '/rsrc/js/application/differential/behavior-diff-radios.js',
),
'javelin-behavior-differential-edit-inline-comments' =>
array(
'uri' => '/res/9d4ca5d7/rsrc/js/application/differential/behavior-edit-inline-comments.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-stratcom',
2 => 'javelin-dom',
3 => 'javelin-util',
4 => 'javelin-vector',
5 => 'differential-inline-comment-editor',
),
'disk' => '/rsrc/js/application/differential/behavior-edit-inline-comments.js',
),
'javelin-behavior-differential-feedback-preview' =>
array(
'uri' => '/res/ab8a7d60/rsrc/js/application/differential/behavior-comment-preview.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-stratcom',
2 => 'javelin-dom',
3 => 'javelin-request',
4 => 'javelin-util',
5 => 'phabricator-shaped-request',
),
'disk' => '/rsrc/js/application/differential/behavior-comment-preview.js',
),
'javelin-behavior-differential-keyboard-navigation' =>
array(
'uri' => '/res/3bdfaec7/rsrc/js/application/differential/behavior-keyboard-nav.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
2 => 'phabricator-keyboard-shortcut',
),
'disk' => '/rsrc/js/application/differential/behavior-keyboard-nav.js',
),
'javelin-behavior-differential-populate' =>
array(
'uri' => '/res/025171e1/rsrc/js/application/differential/behavior-populate.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-request',
2 => 'javelin-util',
3 => 'javelin-dom',
),
'disk' => '/rsrc/js/application/differential/behavior-populate.js',
),
'javelin-behavior-differential-show-all-comments' =>
array(
'uri' => '/res/bcc990f0/rsrc/js/application/differential/behavior-show-all-comments.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-stratcom',
2 => 'javelin-dom',
),
'disk' => '/rsrc/js/application/differential/behavior-show-all-comments.js',
),
'javelin-behavior-differential-show-more' =>
array(
'uri' => '/res/a766c717/rsrc/js/application/differential/behavior-show-more.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
2 => 'javelin-request',
3 => 'javelin-util',
4 => 'javelin-stratcom',
),
'disk' => '/rsrc/js/application/differential/behavior-show-more.js',
),
'javelin-behavior-diffusion-jump-to' =>
array(
'uri' => '/res/4b63e436/rsrc/js/application/diffusion/behavior-jump-to.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-util',
2 => 'javelin-vector',
3 => 'javelin-dom',
),
'disk' => '/rsrc/js/application/diffusion/behavior-jump-to.js',
),
'javelin-behavior-diffusion-pull-lastmodified' =>
array(
'uri' => '/res/29fe2790/rsrc/js/application/diffusion/behavior-pull-lastmodified.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
2 => 'javelin-util',
3 => 'javelin-request',
),
'disk' => '/rsrc/js/application/diffusion/behavior-pull-lastmodified.js',
),
'javelin-behavior-error-log' =>
array(
'uri' => '/res/a5cb42a5/rsrc/js/application/core/behavior-error-log.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-dom',
),
'disk' => '/rsrc/js/application/core/behavior-error-log.js',
),
'javelin-behavior-herald-rule-editor' =>
array(
'uri' => '/res/77a0c945/rsrc/js/application/herald/herald-rule-editor.js',
'type' => 'js',
'requires' =>
array(
0 => 'herald-rule-editor',
1 => 'javelin-behavior',
),
'disk' => '/rsrc/js/application/herald/herald-rule-editor.js',
),
'javelin-behavior-maniphest-project-create' =>
array(
'uri' => '/res/85a0eaf9/rsrc/js/application/maniphest/behavior-project-create.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
2 => 'javelin-stratcom',
3 => 'javelin-workflow',
),
'disk' => '/rsrc/js/application/maniphest/behavior-project-create.js',
),
'javelin-behavior-maniphest-transaction-controls' =>
array(
'uri' => '/res/94a2a395/rsrc/js/application/maniphest/behavior-transaction-controls.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
2 => 'javelin-tokenizer',
3 => 'javelin-typeahead',
4 => 'javelin-typeahead-preloaded-source',
),
'disk' => '/rsrc/js/application/maniphest/behavior-transaction-controls.js',
),
'javelin-behavior-maniphest-transaction-expand' =>
array(
'uri' => '/res/966410de/rsrc/js/application/maniphest/behavior-transaction-expand.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
2 => 'javelin-workflow',
3 => 'javelin-stratcom',
),
'disk' => '/rsrc/js/application/maniphest/behavior-transaction-expand.js',
),
'javelin-behavior-maniphest-transaction-preview' =>
array(
'uri' => '/res/44e86555/rsrc/js/application/maniphest/behavior-transaction-preview.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
2 => 'javelin-util',
3 => 'phabricator-shaped-request',
),
'disk' => '/rsrc/js/application/maniphest/behavior-transaction-preview.js',
),
'javelin-behavior-owners-path-editor' =>
array(
'uri' => '/res/9cf78ffc/rsrc/js/application/owners/owners-path-editor.js',
'type' => 'js',
'requires' =>
array(
0 => 'owners-path-editor',
1 => 'javelin-behavior',
),
'disk' => '/rsrc/js/application/owners/owners-path-editor.js',
),
'javelin-behavior-phabricator-keyboard-shortcuts' =>
array(
'uri' => '/res/94b009e2/rsrc/js/application/core/behavior-keyboard-shortcuts.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-workflow',
2 => 'javelin-json',
3 => 'phabricator-keyboard-shortcut',
),
'disk' => '/rsrc/js/application/core/behavior-keyboard-shortcuts.js',
),
'javelin-behavior-phabricator-object-selector' =>
array(
'uri' => '/res/34f9a11e/rsrc/js/application/core/behavior-object-selector.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-dom',
2 => 'javelin-request',
3 => 'javelin-util',
4 => 'javelin-stratcom',
),
'disk' => '/rsrc/js/application/core/behavior-object-selector.js',
),
'javelin-behavior-phabricator-watch-anchor' =>
array(
'uri' => '/res/bb6fa5b2/rsrc/js/application/core/behavior-watch-anchor.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-stratcom',
2 => 'javelin-util',
3 => 'javelin-dom',
),
'disk' => '/rsrc/js/application/core/behavior-watch-anchor.js',
),
'javelin-behavior-workflow' =>
array(
'uri' => '/res/079f49c3/rsrc/js/application/core/behavior-workflow.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-stratcom',
2 => 'javelin-workflow',
),
'disk' => '/rsrc/js/application/core/behavior-workflow.js',
),
'javelin-dom' =>
array(
'uri' => '/res/34e7f2b5/rsrc/js/javelin/lib/DOM.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-magical-init',
1 => 'javelin-install',
2 => 'javelin-util',
3 => 'javelin-vector',
4 => 'javelin-stratcom',
),
'disk' => '/rsrc/js/javelin/lib/DOM.js',
),
'javelin-event' =>
array(
'uri' => '/res/25c7c9e8/rsrc/js/javelin/core/Event.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
),
'disk' => '/rsrc/js/javelin/core/Event.js',
),
'javelin-install' =>
array(
'uri' => '/res/b6692f42/rsrc/js/javelin/core/install.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-util',
1 => 'javelin-magical-init',
),
'disk' => '/rsrc/js/javelin/core/install.js',
),
'javelin-json' =>
array(
'uri' => '/res/f23dbfbd/rsrc/js/javelin/lib/JSON.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-util',
),
'disk' => '/rsrc/js/javelin/lib/JSON.js',
),
'javelin-magical-init' =>
array(
'uri' => '/res/6a069362/rsrc/js/javelin/core/init.js',
'type' => 'js',
'requires' =>
array(
),
'disk' => '/rsrc/js/javelin/core/init.js',
),
'javelin-mask' =>
array(
'uri' => '/res/28e3bd9c/rsrc/js/javelin/lib/Mask.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-vector',
2 => 'javelin-dom',
),
'disk' => '/rsrc/js/javelin/lib/Mask.js',
),
'javelin-request' =>
array(
'uri' => '/res/786bfe6f/rsrc/js/javelin/lib/Request.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-stratcom',
2 => 'javelin-util',
3 => 'javelin-behavior',
4 => 'javelin-json',
),
'disk' => '/rsrc/js/javelin/lib/Request.js',
),
'javelin-stratcom' =>
array(
'uri' => '/res/d6cf4631/rsrc/js/javelin/core/Stratcom.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-event',
2 => 'javelin-util',
3 => 'javelin-magical-init',
),
'disk' => '/rsrc/js/javelin/core/Stratcom.js',
),
'javelin-tokenizer' =>
array(
'uri' => '/res/c2dbba74/rsrc/js/javelin/lib/control/tokenizer/Tokenizer.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-dom',
1 => 'javelin-util',
2 => 'javelin-stratcom',
3 => 'javelin-install',
),
'disk' => '/rsrc/js/javelin/lib/control/tokenizer/Tokenizer.js',
),
'javelin-typeahead' =>
array(
'uri' => '/res/354d32f1/rsrc/js/javelin/lib/control/typeahead/Typeahead.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-dom',
2 => 'javelin-vector',
3 => 'javelin-util',
),
'disk' => '/rsrc/js/javelin/lib/control/typeahead/Typeahead.js',
),
'javelin-typeahead-composite-source' =>
array(
'uri' => '/res/9873d21c/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-typeahead-source',
2 => 'javelin-util',
),
'disk' => '/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js',
),
'javelin-typeahead-normalizer' =>
array(
'uri' => '/res/a5d60e3c/rsrc/js/javelin/lib/control/typeahead/normalizer/TypeaheadNormalizer.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
),
'disk' => '/rsrc/js/javelin/lib/control/typeahead/normalizer/TypeaheadNormalizer.js',
),
'javelin-typeahead-ondemand-source' =>
array(
'uri' => '/res/b2e527e4/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-util',
2 => 'javelin-stratcom',
3 => 'javelin-request',
4 => 'javelin-typeahead-source',
),
'disk' => '/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js',
),
'javelin-typeahead-preloaded-source' =>
array(
'uri' => '/res/f3c1e7c7/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-util',
2 => 'javelin-stratcom',
3 => 'javelin-request',
4 => 'javelin-typeahead-source',
),
'disk' => '/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js',
),
'javelin-typeahead-source' =>
array(
'uri' => '/res/8a3aa262/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadSource.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-util',
2 => 'javelin-dom',
3 => 'javelin-typeahead-normalizer',
),
'disk' => '/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadSource.js',
),
'javelin-uri' =>
array(
'uri' => '/res/1c0ead43/rsrc/js/javelin/lib/URI.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-util',
2 => 'javelin-stratcom',
),
'disk' => '/rsrc/js/javelin/lib/URI.js',
),
'javelin-util' =>
array(
'uri' => '/res/725cc90d/rsrc/js/javelin/core/util.js',
'type' => 'js',
'requires' =>
array(
),
'disk' => '/rsrc/js/javelin/core/util.js',
),
'javelin-vector' =>
array(
'uri' => '/res/50535cb8/rsrc/js/javelin/lib/Vector.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-event',
),
'disk' => '/rsrc/js/javelin/lib/Vector.js',
),
'javelin-workflow' =>
array(
'uri' => '/res/91a04640/rsrc/js/javelin/lib/Workflow.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-stratcom',
1 => 'javelin-request',
2 => 'javelin-dom',
3 => 'javelin-vector',
4 => 'javelin-install',
5 => 'javelin-util',
6 => 'javelin-mask',
7 => 'javelin-uri',
),
'disk' => '/rsrc/js/javelin/lib/Workflow.js',
),
'mainphest-task-detail-css' =>
array(
'uri' => '/res/dbefc148/rsrc/css/application/maniphest/task-detail.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/maniphest/task-detail.css',
),
'maniphest-task-summary-css' =>
array(
'uri' => '/res/14cb4b5d/rsrc/css/application/maniphest/task-summary.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/maniphest/task-summary.css',
),
'maniphest-transaction-detail-css' =>
array(
'uri' => '/res/149fccab/rsrc/css/application/maniphest/transaction-detail.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/maniphest/transaction-detail.css',
),
'multirow-row-manager' =>
array(
'uri' => '/res/0a9b3dee/rsrc/js/application/core/MultirowRowManager.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-stratcom',
2 => 'javelin-dom',
3 => 'javelin-util',
),
'disk' => '/rsrc/js/application/core/MultirowRowManager.js',
),
'owners-path-editor' =>
array(
'uri' => '/res/e6c51eb6/rsrc/js/application/owners/OwnersPathEditor.js',
'type' => 'js',
'requires' =>
array(
0 => 'multirow-row-manager',
1 => 'javelin-install',
2 => 'path-typeahead',
3 => 'javelin-dom',
4 => 'javelin-util',
),
'disk' => '/rsrc/js/application/owners/OwnersPathEditor.js',
),
'owners-path-editor-css' =>
array(
'uri' => '/res/9bc5332c/rsrc/css/application/owners/owners-path-editor.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/owners/owners-path-editor.css',
),
'path-typeahead' =>
array(
'uri' => '/res/1343345d/rsrc/js/application/herald/PathTypeahead.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-typeahead',
2 => 'javelin-dom',
3 => 'javelin-request',
4 => 'javelin-typeahead-ondemand-source',
5 => 'javelin-util',
),
'disk' => '/rsrc/js/application/herald/PathTypeahead.js',
),
'phabricator-core-buttons-css' =>
array(
'uri' => '/res/3059cf79/rsrc/css/core/buttons.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/core/buttons.css',
),
'phabricator-core-css' =>
array(
'uri' => '/res/bd20d04b/rsrc/css/core/core.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/core/core.css',
),
'phabricator-countdown-css' =>
array(
'uri' => '/res/0f646281/rsrc/css/application/countdown/timer.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/countdown/timer.css',
),
'phabricator-directory-css' =>
array(
'uri' => '/res/a3d307c5/rsrc/css/application/directory/phabricator-directory.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/directory/phabricator-directory.css',
),
'phabricator-drag-and-drop-file-upload' =>
array(
'uri' => '/res/63a06ad9/rsrc/js/application/core/DragAndDropFileUpload.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-util',
2 => 'javelin-request',
3 => 'javelin-dom',
4 => 'javelin-uri',
),
'disk' => '/rsrc/js/application/core/DragAndDropFileUpload.js',
),
'phabricator-feed-css' =>
array(
'uri' => '/res/32e5879b/rsrc/css/application/feed/feed.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/feed/feed.css',
),
'phabricator-keyboard-shortcut' =>
array(
'uri' => '/res/beed38cd/rsrc/js/application/core/KeyboardShortcut.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-util',
2 => 'phabricator-keyboard-shortcut-manager',
),
'disk' => '/rsrc/js/application/core/KeyboardShortcut.js',
),
'phabricator-keyboard-shortcut-manager' =>
array(
'uri' => '/res/04767571/rsrc/js/application/core/KeyboardShortcutManager.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-util',
2 => 'javelin-stratcom',
3 => 'javelin-dom',
4 => 'javelin-vector',
),
'disk' => '/rsrc/js/application/core/KeyboardShortcutManager.js',
),
'phabricator-object-selector-css' =>
array(
'uri' => '/res/608461d2/rsrc/css/application/objectselector/object-selector.css',
'type' => 'css',
'requires' =>
array(
0 => 'aphront-dialog-view-css',
),
'disk' => '/rsrc/css/application/objectselector/object-selector.css',
),
'phabricator-profile-css' =>
array(
'uri' => '/res/ebe1ac2f/rsrc/css/application/profile/profile-view.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/profile/profile-view.css',
),
'phabricator-remarkup-css' =>
array(
'uri' => '/res/7ca89111/rsrc/css/core/remarkup.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/core/remarkup.css',
),
'phabricator-search-results-css' =>
array(
'uri' => '/res/f8a86e27/rsrc/css/application/search/search-results.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/search/search-results.css',
),
'phabricator-shaped-request' =>
array(
'uri' => '/res/d7ba774e/rsrc/js/application/core/ShapedRequest.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-util',
2 => 'javelin-request',
),
'disk' => '/rsrc/js/application/core/ShapedRequest.js',
),
'phabricator-slowvote-css' =>
array(
'uri' => '/res/94d20443/rsrc/css/application/slowvote/slowvote.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/slowvote/slowvote.css',
),
'phabricator-standard-page-view' =>
array(
'uri' => '/res/e8238633/rsrc/css/application/base/standard-page-view.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/base/standard-page-view.css',
),
'phabricator-ui-example-css' =>
array(
'uri' => '/res/0cef078b/rsrc/css/application/uiexample/example.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/uiexample/example.css',
),
'syntax-highlighting-css' =>
array(
'uri' => '/res/e5cc3d88/rsrc/css/core/syntax.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/core/syntax.css',
),
), array (
'packages' =>
array (
'03ef179e' =>
array (
'name' => 'diffusion.pkg.css',
'symbols' =>
array (
0 => 'diffusion-commit-view-css',
),
'uri' => '/res/pkg/03ef179e/diffusion.pkg.css',
'type' => 'css',
),
'25f94e94' =>
array (
'name' => 'typeahead.pkg.js',
'symbols' =>
array (
0 => 'javelin-typeahead',
1 => 'javelin-typeahead-normalizer',
2 => 'javelin-typeahead-source',
3 => 'javelin-typeahead-preloaded-source',
4 => 'javelin-typeahead-ondemand-source',
5 => 'javelin-tokenizer',
6 => 'javelin-behavior-aphront-basic-tokenizer',
),
'uri' => '/res/pkg/25f94e94/typeahead.pkg.js',
'type' => 'js',
),
'307df223' =>
array (
'name' => 'javelin.pkg.js',
'symbols' =>
array (
0 => 'javelin-util',
1 => 'javelin-install',
2 => 'javelin-event',
3 => 'javelin-stratcom',
4 => 'javelin-behavior',
5 => 'javelin-request',
6 => 'javelin-vector',
7 => 'javelin-dom',
8 => 'javelin-json',
9 => 'javelin-uri',
),
'uri' => '/res/pkg/307df223/javelin.pkg.js',
'type' => 'js',
),
'95b66c1a' =>
array (
'name' => 'differential.pkg.css',
'symbols' =>
array (
0 => 'differential-core-view-css',
1 => 'differential-changeset-view-css',
2 => 'differential-revision-detail-css',
3 => 'differential-revision-history-css',
4 => 'differential-table-of-contents-css',
5 => 'differential-revision-comment-css',
6 => 'differential-revision-add-comment-css',
7 => 'differential-revision-comment-list-css',
),
'uri' => '/res/pkg/95b66c1a/differential.pkg.css',
'type' => 'css',
),
'a06761eb' =>
array (
'name' => 'core.pkg.css',
'symbols' =>
array (
0 => 'phabricator-core-css',
1 => 'phabricator-core-buttons-css',
2 => 'phabricator-standard-page-view',
3 => 'aphront-dialog-view-css',
4 => 'aphront-form-view-css',
5 => 'aphront-panel-view-css',
6 => 'aphront-side-nav-view-css',
7 => 'aphront-table-view-css',
8 => 'aphront-crumbs-view-css',
9 => 'aphront-tokenizer-control-css',
10 => 'aphront-typeahead-control-css',
11 => 'aphront-list-filter-view-css',
12 => 'phabricator-directory-css',
13 => 'phabricator-remarkup-css',
14 => 'syntax-highlighting-css',
),
'uri' => '/res/pkg/a06761eb/core.pkg.css',
'type' => 'css',
),
'd0713563' =>
array (
'name' => 'workflow.pkg.js',
'symbols' =>
array (
0 => 'javelin-mask',
1 => 'javelin-workflow',
2 => 'javelin-behavior-workflow',
3 => 'javelin-behavior-aphront-form-disable-on-submit',
4 => 'phabricator-keyboard-shortcut-manager',
5 => 'phabricator-keyboard-shortcut',
6 => 'javelin-behavior-phabricator-keyboard-shortcuts',
),
'uri' => '/res/pkg/d0713563/workflow.pkg.js',
'type' => 'js',
),
'da416e1c' =>
array (
'name' => 'differential.pkg.js',
'symbols' =>
array (
0 => 'javelin-behavior-differential-feedback-preview',
1 => 'javelin-behavior-differential-edit-inline-comments',
2 => 'javelin-behavior-differential-populate',
3 => 'javelin-behavior-differential-show-more',
4 => 'javelin-behavior-differential-diff-radios',
),
'uri' => '/res/pkg/da416e1c/differential.pkg.js',
'type' => 'js',
),
),
'reverse' =>
array (
'aphront-crumbs-view-css' => 'a06761eb',
'aphront-dialog-view-css' => 'a06761eb',
'aphront-form-view-css' => 'a06761eb',
'aphront-list-filter-view-css' => 'a06761eb',
'aphront-panel-view-css' => 'a06761eb',
'aphront-side-nav-view-css' => 'a06761eb',
'aphront-table-view-css' => 'a06761eb',
'aphront-tokenizer-control-css' => 'a06761eb',
'aphront-typeahead-control-css' => 'a06761eb',
'differential-changeset-view-css' => '95b66c1a',
'differential-core-view-css' => '95b66c1a',
'differential-revision-add-comment-css' => '95b66c1a',
'differential-revision-comment-css' => '95b66c1a',
'differential-revision-comment-list-css' => '95b66c1a',
'differential-revision-detail-css' => '95b66c1a',
'differential-revision-history-css' => '95b66c1a',
'differential-table-of-contents-css' => '95b66c1a',
'diffusion-commit-view-css' => '03ef179e',
'javelin-behavior' => '307df223',
'javelin-behavior-aphront-basic-tokenizer' => '25f94e94',
'javelin-behavior-aphront-form-disable-on-submit' => 'd0713563',
'javelin-behavior-differential-diff-radios' => 'da416e1c',
'javelin-behavior-differential-edit-inline-comments' => 'da416e1c',
'javelin-behavior-differential-feedback-preview' => 'da416e1c',
'javelin-behavior-differential-populate' => 'da416e1c',
'javelin-behavior-differential-show-more' => 'da416e1c',
'javelin-behavior-phabricator-keyboard-shortcuts' => 'd0713563',
'javelin-behavior-workflow' => 'd0713563',
'javelin-dom' => '307df223',
'javelin-event' => '307df223',
'javelin-install' => '307df223',
'javelin-json' => '307df223',
'javelin-mask' => 'd0713563',
'javelin-request' => '307df223',
'javelin-stratcom' => '307df223',
'javelin-tokenizer' => '25f94e94',
'javelin-typeahead' => '25f94e94',
'javelin-typeahead-normalizer' => '25f94e94',
'javelin-typeahead-ondemand-source' => '25f94e94',
'javelin-typeahead-preloaded-source' => '25f94e94',
'javelin-typeahead-source' => '25f94e94',
'javelin-uri' => '307df223',
'javelin-util' => '307df223',
'javelin-vector' => '307df223',
'javelin-workflow' => 'd0713563',
'phabricator-core-buttons-css' => 'a06761eb',
'phabricator-core-css' => 'a06761eb',
'phabricator-directory-css' => 'a06761eb',
'phabricator-keyboard-shortcut' => 'd0713563',
'phabricator-keyboard-shortcut-manager' => 'd0713563',
'phabricator-remarkup-css' => 'a06761eb',
'phabricator-standard-page-view' => 'a06761eb',
'syntax-highlighting-css' => 'a06761eb',
),
));
diff --git a/src/aphront/console/plugin/base/DarkConsolePlugin.php b/src/aphront/console/plugin/base/DarkConsolePlugin.php
index 7350979925..5fe185d105 100644
--- a/src/aphront/console/plugin/base/DarkConsolePlugin.php
+++ b/src/aphront/console/plugin/base/DarkConsolePlugin.php
@@ -1,88 +1,92 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
abstract class DarkConsolePlugin {
private $data;
private $request;
private $core;
abstract public function getName();
abstract public function getDescription();
abstract public function render();
public function __construct() {
}
public function setConsoleCore(DarkConsoleCore $core) {
$this->core = $core;
return $this;
}
public function getConsoleCore() {
return $this->core;
}
public function generateData() {
return null;
}
public function setData($data) {
$this->data = $data;
return $this;
}
public function getData() {
return $this->data;
}
public function setRequest($request) {
$this->request = $request;
return $this;
}
public function getRequest() {
return $this->request;
}
+ public function getRequestURI() {
+ return $this->getRequest()->getRequestURI();
+ }
+
public function isPermanent() {
return false;
}
public function shouldStartup() {
return true;
}
public function didStartup() {
return null;
}
public function willShutdown() {
return null;
}
public function didShutdown() {
return null;
}
public function processRequest() {
return null;
}
}
diff --git a/src/aphront/console/plugin/services/DarkConsoleServicesPlugin.php b/src/aphront/console/plugin/services/DarkConsoleServicesPlugin.php
index dc053dfa6e..5cda555c6f 100644
--- a/src/aphront/console/plugin/services/DarkConsoleServicesPlugin.php
+++ b/src/aphront/console/plugin/services/DarkConsoleServicesPlugin.php
@@ -1,95 +1,276 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class DarkConsoleServicesPlugin extends DarkConsolePlugin {
protected $observations;
public function getName() {
return 'Services';
}
public function getDescription() {
return 'Information about services.';
}
public function generateData() {
+ $log = PhutilServiceProfiler::getInstance()->getServiceCallLog();
+ foreach ($log as $key => $entry) {
+ $config = $entry['config'];
+ unset($log[$key]['config']);
+
+ if (empty($_REQUEST['__analyze__'])) {
+ $log[$key]['explain'] = array(
+ 'sev' => 7,
+ 'size' => null,
+ 'reason' => 'Disabled',
+ );
+ // Query analysis is disabled for this request, so don't do any of it.
+ continue;
+ }
+
+ if ($entry['type'] != 'query') {
+ continue;
+ }
+
+ // For each SELECT query, go issue an EXPLAIN on it so we can flag stuff
+ // causing table scans, etc.
+ if (preg_match('/^\s*SELECT\b/i', $entry['query'])) {
+ $conn = new AphrontMySQLDatabaseConnection($entry['config']);
+ try {
+ $explain = queryfx_all(
+ $conn,
+ 'EXPLAIN %Q',
+ $entry['query']);
+
+ $badness = 0;
+ $size = 1;
+ $reason = null;
+
+ foreach ($explain as $table) {
+ $size *= (int)$table['rows'];
+
+ switch ($table['type']) {
+ case 'index':
+ $cur_badness = 1;
+ $cur_reason = 'Index';
+ break;
+ case 'const':
+ $cur_badness = 1;
+ $cur_reason = 'Const';
+ break;
+ case 'eq_ref';
+ $cur_badness = 2;
+ $cur_reason = 'EqRef';
+ break;
+ case 'range':
+ $cur_badness = 3;
+ $cur_reason = 'Range';
+ break;
+ case 'ref':
+ $cur_badness = 3;
+ $cur_reason = 'Ref';
+ break;
+ case 'ALL':
+ if (preg_match('/Using where/', $table['Extra'])) {
+ if ($table['rows'] < 256 && !empty($table['possible_keys'])) {
+ $cur_badness = 2;
+ $cur_reason = 'Small Table Scan';
+ } else {
+ $cur_badness = 6;
+ $cur_reason = 'TABLE SCAN!';
+ }
+ } else {
+ $cur_badness = 3;
+ $cur_reason = 'Whole Table';
+ }
+ break;
+ default:
+ if (preg_match('/No tables used/i', $table['Extra'])) {
+ $cur_badness = 1;
+ $cur_reason = 'No Tables';
+ } else if (preg_match('/Impossible/i', $table['Extra'])) {
+ $cur_badness = 1;
+ $cur_reason = 'Empty';
+ } else {
+ $cur_badness = 4;
+ $cur_reason = "Can't Analyze";
+ }
+ break;
+ }
+
+ if ($cur_badness > $badness) {
+ $badness = $cur_badness;
+ $reason = $cur_reason;
+ }
+ }
+
+ $log[$key]['explain'] = array(
+ 'sev' => $badness,
+ 'size' => $size,
+ 'reason' => $reason,
+ );
+ } catch (Exception $ex) {
+ $log[$key]['explain'] = array(
+ 'sev' => 5,
+ 'size' => null,
+ 'reason' => $ex->getMessage(),
+ );
+ }
+ }
+ }
+
return array(
'start' => $GLOBALS['__start__'],
- 'log' => PhutilServiceProfiler::getInstance()->getServiceCallLog(),
+ 'end' => microtime(true),
+ 'log' => $log,
);
}
public function render() {
$data = $this->getData();
$log = $data['log'];
+ $results = array();
+
+ $results[] =
+ '<div class="dark-console-panel-header">'.
+ phutil_render_tag(
+ 'a',
+ array(
+ 'href' => $this->getRequestURI()->alter('__analyze__', true),
+ 'class' => isset($_REQUEST['__analyze__'])
+ ? 'disabled button'
+ : 'green button',
+ ),
+ 'Analyze Query Plans').
+ '<h1>Calls to External Services</h1>'.
+ '<div style="clear: both;"></div>'.
+ '</div>';
+
+ $page_total = $data['end'] - $data['start'];
+ $totals = array();
+ $counts = array();
+
+ foreach ($log as $row) {
+ $totals[$row['type']] += $row['duration'];
+ $counts[$row['type']]++;
+ }
+ $totals['All'] = array_sum($totals);
+ $counts['All'] = array_sum($counts);
+
+ $table = new AphrontTableView();
+ $summary = array();
+ foreach ($totals as $type => $total) {
+ $summary[] = array(
+ $type,
+ number_format($counts[$type]),
+ number_format((int)(1000000 * $totals[$type])).' us',
+ sprintf('%.1f%%', 100 * $totals[$type] / $page_total),
+ );
+ }
+ $summary_table = new AphrontTableView($summary);
+ $summary_table->setColumnClasses(
+ array(
+ '',
+ 'n',
+ 'n',
+ 'wide',
+ ));
+ $summary_table->setHeaders(
+ array(
+ 'Type',
+ 'Count',
+ 'Total Cost',
+ 'Page Weight',
+ ));
+
+ $results[] = $summary_table->render();
$rows = array();
foreach ($log as $row) {
+ $analysis = null;
+
switch ($row['type']) {
case 'query':
$info = $row['query'];
+ $info = wordwrap($info, 128, "\n", true);
+
+ if (!empty($row['explain'])) {
+ $analysis = phutil_escape_html($row['explain']['reason']);
+ $analysis = phutil_render_tag(
+ 'span',
+ array(
+ 'class' => 'explain-sev-'.$row['explain']['sev'],
+ ),
+ $analysis);
+ }
+
$info = phutil_escape_html($info);
break;
case 'connect':
$info = $row['host'].':'.$row['database'];
$info = phutil_escape_html($info);
break;
case 'exec':
$info = $row['command'];
$info = phutil_escape_html($info);
break;
case 'conduit':
$info = $row['method'];
$info = phutil_escape_html($info);
break;
default:
$info = '-';
break;
}
$rows[] = array(
phutil_escape_html($row['type']),
'+'.number_format(1000 * ($row['begin'] - $data['start'])).' ms',
number_format(1000000 * $row['duration']).' us',
$info,
+ $analysis,
);
}
$table = new AphrontTableView($rows);
$table->setColumnClasses(
array(
null,
'n',
'n',
- 'wide wrap',
+ 'wide',
+ '',
));
$table->setHeaders(
array(
'Event',
'Start',
'Duration',
'Details',
+ 'Analysis',
));
- return $table->render();
+ $results[] = $table->render();
+
+ return implode("\n", $results);
}
}
diff --git a/src/aphront/console/plugin/services/__init__.php b/src/aphront/console/plugin/services/__init__.php
index 00234db119..a89b976384 100644
--- a/src/aphront/console/plugin/services/__init__.php
+++ b/src/aphront/console/plugin/services/__init__.php
@@ -1,16 +1,18 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'aphront/console/plugin/base');
+phutil_require_module('phabricator', 'storage/connection/mysql');
+phutil_require_module('phabricator', 'storage/queryfx');
phutil_require_module('phabricator', 'view/control/table');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'serviceprofiler');
phutil_require_source('DarkConsoleServicesPlugin.php');
diff --git a/src/aphront/console/plugin/xhprof/DarkConsoleXHProfPlugin.php b/src/aphront/console/plugin/xhprof/DarkConsoleXHProfPlugin.php
index c12181493b..31550e98a2 100644
--- a/src/aphront/console/plugin/xhprof/DarkConsoleXHProfPlugin.php
+++ b/src/aphront/console/plugin/xhprof/DarkConsoleXHProfPlugin.php
@@ -1,135 +1,157 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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 getDescription() {
return 'Provides detailed PHP profiling information through XHProf.';
}
public function generateData() {
return $this->xhprofID;
}
public function getXHProfRunID() {
return $this->xhprofID;
}
public function render() {
if (!DarkConsoleXHProfPluginAPI::isProfilerAvailable()) {
+ $href = PhabricatorEnv::getDoclink('article/Installation_Guide.html');
+ $install_guide = phutil_render_tag(
+ 'a',
+ array(
+ 'href' => $href,
+ 'class' => 'bright-link',
+ ),
+ 'Installation Guide');
return
- '<p>The "xhprof" PHP extension is not available. Install xhprof '.
- 'to enable the XHProf plugin.';
+ '<div class="dark-console-no-content">'.
+ 'The "xhprof" PHP extension is not available. Install xhprof '.
+ 'to enable the XHProf console plugin. You can find instructions in '.
+ 'the '.$install_guide.'.'.
+ '</div>';
}
+ $result = array();
+
$run = $this->getXHProfRunID();
- if ($run) {
- return '<a href="/xhprof/profile/'.$run.'/">View Run</a>';
- } else {
- $hidden = array();
- $data = array('__profile__' => 'page') + $_GET;
- foreach ($data as $k => $v) {
- $hidden[] = phutil_render_tag(
- 'input',
+ $header =
+ '<div class="dark-console-panel-header">'.
+ phutil_render_tag(
+ 'a',
array(
- 'type' => 'hidden',
- 'name' => $k,
- 'value' => $v,
- ));
- }
- $hidden = implode("\n", $hidden);
-
+ 'href' => $this->getRequestURI()->alter('__profile__', 'page'),
+ 'class' => $run
+ ? 'disabled button'
+ : 'green button',
+ ),
+ 'Profile Page').
+ '<h1>XHProf Profiler</h1>'.
+ '</div>';
+ $result[] = $header;
- return
- '<form method="get">'.
- $hidden.
- '<button>Enable XHProf</button>'.
- '</form>';
+ if ($run) {
+ $result[] =
+ '<a href="/xhprof/profile/'.$run.'/" '.
+ 'class="bright-link" '.
+ 'style="float: right; margin: 1em 2em 0 0;'.
+ 'font-weight: bold;" '.
+ 'target="_blank">Profile Permalink</a>'.
+ '<iframe src="/xhprof/profile/'.$run.'/?frame=true"></iframe>';
+ } else {
+ $result[] =
+ '<div class="dark-console-no-content">'.
+ 'Profiling was not enabled for this page. Use the button above '.
+ 'to enable it.'.
+ '</div>';
}
+
+ return implode("\n", $result);
}
public function willShutdown() {
if (isset($_REQUEST['__profile__']) &&
$_REQUEST['__profile__'] != 'all') {
$this->xhprofID = DarkConsoleXHProfPluginAPI::stopProfiler();
}
}
}
/*
public function render() {
$run = $this->getData();
if ($run) {
$uri = 'http://www.intern.facebook.com/intern/phprof/?run='.$run;
return
<x:frag>
<h1>XHProf Results</h1>
<div class="XHProfPlugin">
<a href={$uri} target="_blank" class="XHProfPlugin">Permalink</a>
<iframe src={$uri} width="100%" height="600" />
</div>
</x:frag>;
}
$uri = URI::getRequestURI();
return
<x:frag>
<h1>XHProf</h1>
<form action={$uri} method="get" class="EnableFeature">
<fieldset>
<legend>Enable Profiling</legend>
<p>Profiling was not enabled for this request. Click the button
below to rerun the request with profiling enabled.</p>
<button type="submit" name="_profile_" value="all"
style="margin: 2px 1em; width: 75%;">
Profile Page (With Includes)
</button>
<button type="submit" name="_profile_" value="exec"
style="margin: 2px 1em; width: 75%;">
Profile Page (No Includes)
</button>
</fieldset>
</form>
</x:frag>;
}
public function didShutdown() {
if ($this->xhprofData) {
require_module_lazy('profiling/phprof');
$this->xhprofID = phprof_save_run($this->xhprofData);
}
}
}
*/
diff --git a/src/aphront/console/plugin/xhprof/__init__.php b/src/aphront/console/plugin/xhprof/__init__.php
index 32fd5d88d9..1e2cbd9cf3 100644
--- a/src/aphront/console/plugin/xhprof/__init__.php
+++ b/src/aphront/console/plugin/xhprof/__init__.php
@@ -1,15 +1,16 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'aphront/console/plugin/base');
phutil_require_module('phabricator', 'aphront/console/plugin/xhprof/api');
+phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phutil', 'markup');
phutil_require_source('DarkConsoleXHProfPlugin.php');
diff --git a/src/applications/files/controller/list/PhabricatorFileListController.php b/src/applications/files/controller/list/PhabricatorFileListController.php
index f78af9fd2c..85befebfcd 100644
--- a/src/applications/files/controller/list/PhabricatorFileListController.php
+++ b/src/applications/files/controller/list/PhabricatorFileListController.php
@@ -1,121 +1,122 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorFileListController extends PhabricatorFileController {
public function processRequest() {
$request = $this->getRequest();
+ $author = null;
$author_username = $request->getStr('author');
if ($author_username) {
$author = id(new PhabricatorUser())->loadOneWhere(
'userName = %s',
$author_username);
if (!$author) {
return id(new Aphront404Response());
}
}
$pager = new AphrontPagerView();
$pager->setOffset($request->getInt('page'));
if ($author) {
$files = id(new PhabricatorFile())->loadAllWhere(
'authorPHID = %s ORDER BY id DESC LIMIT %d, %d',
$author->getPHID(),
$pager->getOffset(),
$pager->getPageSize() + 1);
} else {
$files = id(new PhabricatorFile())->loadAllWhere(
'1 = 1 ORDER BY id DESC LIMIT %d, %d',
$pager->getOffset(),
$pager->getPageSize() + 1);
}
$files = $pager->sliceResults($files);
$pager->setURI($request->getRequestURI(), 'page');
$rows = array();
foreach ($files as $file) {
if ($file->isViewableInBrowser()) {
$view_button = phutil_render_tag(
'a',
array(
'class' => 'small button grey',
'href' => '/file/view/'.$file->getPHID().'/',
),
'View');
} else {
$view_button = null;
}
$rows[] = array(
phutil_escape_html($file->getPHID()),
phutil_escape_html($file->getName()),
phutil_escape_html($file->getByteSize()),
phutil_render_tag(
'a',
array(
'class' => 'small button grey',
'href' => '/file/info/'.$file->getPHID().'/',
),
'Info'),
$view_button,
phutil_render_tag(
'a',
array(
'class' => 'small button grey',
'href' => '/file/download/'.$file->getPHID().'/',
),
'Download'),
);
}
$table = new AphrontTableView($rows);
$table->setHeaders(
array(
'PHID',
'Name',
'Size',
'',
'',
'',
));
$table->setColumnClasses(
array(
null,
'wide',
null,
'action',
'action',
'action',
));
$panel = new AphrontPanelView();
$panel->appendChild($table);
$panel->setHeader('Files');
$panel->setCreateButton('Upload File', '/file/upload/');
$panel->appendChild($pager);
return $this->buildStandardPageResponse($panel, array(
'title' => 'Files',
'tab' => 'files',
));
}
}
diff --git a/src/applications/xhprof/controller/base/PhabricatorXHProfController.php b/src/applications/xhprof/controller/base/PhabricatorXHProfController.php
index fff91acb0d..b6e3b73d48 100644
--- a/src/applications/xhprof/controller/base/PhabricatorXHProfController.php
+++ b/src/applications/xhprof/controller/base/PhabricatorXHProfController.php
@@ -1,34 +1,42 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
abstract class PhabricatorXHProfController extends PhabricatorController {
public function buildStandardPageResponse($view, array $data) {
$page = $this->buildStandardPageView();
$page->setApplicationName('XHProf');
$page->setBaseURI('/xhprof/');
$page->setTitle(idx($data, 'title'));
$page->setGlyph("\xE2\x98\x84");
$page->appendChild($view);
$response = new AphrontWebpageResponse();
+
+ if (isset($data['frame'])) {
+ $response->setFrameable(true);
+ $page->setFrameable(true);
+ $page->setShowChrome(false);
+ $page->setDisableConsole(true);
+ }
+
return $response->setContent($page->render());
}
}
diff --git a/src/applications/xhprof/controller/profile/PhabricatorXHProfProfileController.php b/src/applications/xhprof/controller/profile/PhabricatorXHProfProfileController.php
index 1eca5b23be..cf0b954d7d 100644
--- a/src/applications/xhprof/controller/profile/PhabricatorXHProfProfileController.php
+++ b/src/applications/xhprof/controller/profile/PhabricatorXHProfProfileController.php
@@ -1,63 +1,64 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorXHProfProfileController
extends PhabricatorXHProfController {
private $phid;
public function willProcessRequest(array $data) {
$this->phid = $data['phid'];
}
public function processRequest() {
$file = id(new PhabricatorFile())->loadOneWhere(
'phid = %s',
$this->phid);
if (!$file) {
return new Aphront404Response();
}
$data = $file->loadFileData();
$data = unserialize($data);
if (!$data) {
throw new Exception("Failed to unserialize XHProf profile!");
}
$request = $this->getRequest();
$symbol = $request->getStr('symbol');
if ($symbol) {
$view = new PhabricatorXHProfProfileSymbolView();
$view->setProfileData($data);
$view->setSymbol($symbol);
} else {
$view = new PhabricatorXHProfProfileTopLevelView();
$view->setProfileData($data);
$view->setLimit(100);
}
return $this->buildStandardPageResponse(
$view,
array(
'title' => 'Profile',
+ 'frame' => $request->getBool('frame'),
));
}
}
diff --git a/src/storage/connection/mysql/AphrontMySQLDatabaseConnection.php b/src/storage/connection/mysql/AphrontMySQLDatabaseConnection.php
index 93e120233e..4f5a21bc01 100644
--- a/src/storage/connection/mysql/AphrontMySQLDatabaseConnection.php
+++ b/src/storage/connection/mysql/AphrontMySQLDatabaseConnection.php
@@ -1,270 +1,271 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @group storage
*/
class AphrontMySQLDatabaseConnection extends AphrontDatabaseConnection {
private $config;
private $connection;
private static $connectionCache = array();
public function __construct(array $configuration) {
$this->configuration = $configuration;
}
public function escapeString($string) {
$this->requireConnection();
return mysql_real_escape_string($string, $this->connection);
}
public function escapeColumnName($name) {
return '`'.str_replace('`', '\\`', $name).'`';
}
public function escapeMultilineComment($comment) {
// These can either terminate a comment, confuse the hell out of the parser,
// make MySQL execute the comment as a query, or, in the case of semicolon,
// are quasi-dangerous because the semicolon could turn a broken query into
// a working query plus an ignored query.
static $map = array(
'--' => '(DOUBLEDASH)',
'*/' => '(STARSLASH)',
'//' => '(SLASHSLASH)',
'#' => '(HASH)',
'!' => '(BANG)',
';' => '(SEMICOLON)',
);
$comment = str_replace(
array_keys($map),
array_values($map),
$comment);
// For good measure, kill anything else that isn't a nice printable
// character.
$comment = preg_replace('/[^\x20-\x7F]+/', ' ', $comment);
return '/* '.$comment.' */';
}
public function escapeStringForLikeClause($value) {
$value = $this->escapeString($value);
// Ideally the query shouldn't be modified after safely escaping it,
// but we need to escape _ and % within LIKE terms.
$value = str_replace(
// Even though we've already escaped, we need to replace \ with \\
// because MYSQL unescapes twice inside a LIKE clause. See note
// at mysql.com. However, if the \ is being used to escape a single
// quote ('), then the \ should not be escaped. Thus, after all \
// are replaced with \\, we need to revert instances of \\' back to
// \'.
array('\\', '\\\\\'', '_', '%'),
array('\\\\', '\\\'', '\_', '\%'),
$value);
return $value;
}
private function getConfiguration($key, $default = null) {
return idx($this->configuration, $key, $default);
}
private function closeConnection() {
if ($this->connection) {
$this->connection = null;
$key = $this->getConnectionCacheKey();
unset(self::$connectionCache[$key]);
}
}
private function getConnectionCacheKey() {
$user = $this->getConfiguration('user');
$host = $this->getConfiguration('host');
$database = $this->getConfiguration('database');
return "{$user}:{$host}:{$database}";
}
private function establishConnection() {
$this->closeConnection();
$user = $this->getConfiguration('user');
$host = $this->getConfiguration('host');
$database = $this->getConfiguration('database');
$key = $this->getConnectionCacheKey();
if (isset(self::$connectionCache[$key])) {
$this->connection = self::$connectionCache[$key];
return;
}
$start = microtime(true);
if (!function_exists('mysql_connect')) {
// We have to '@' the actual call since it can spew all sorts of silly
// noise, but it will also silence fatals caused by not having MySQL
// installed, which has bitten me on three separate occasions. Make sure
// such failures are explicit and loud.
throw new Exception(
"About to call mysql_connect(), but the PHP MySQL extension is not ".
"available!");
}
$profiler = PhutilServiceProfiler::getInstance();
$call_id = $profiler->beginServiceCall(
array(
'type' => 'connect',
'host' => $host,
'database' => $database,
));
try {
$conn = @mysql_connect(
$host,
$user,
$this->getConfiguration('pass'),
$new_link = true,
$flags = 0);
if (!$conn) {
$errno = mysql_errno();
$error = mysql_error();
throw new AphrontQueryConnectionException(
"Attempt to connect to {$user}@{$host} failed with error #{$errno}: ".
"{$error}.");
}
if ($database !== null) {
$ret = @mysql_select_db($database, $conn);
if (!$ret) {
$this->throwQueryException($conn);
}
}
$profiler->endServiceCall($call_id, array());
} catch (Exception $ex) {
$profiler->endServiceCall($call_id, array());
throw $ex;
}
self::$connectionCache[$key] = $conn;
$this->connection = $conn;
}
public function getInsertID() {
return mysql_insert_id($this->requireConnection());
}
public function getAffectedRows() {
return mysql_affected_rows($this->requireConnection());
}
public function getTransactionKey() {
return (int)$this->requireConnection();
}
private function requireConnection() {
if (!$this->connection) {
$this->establishConnection();
}
return $this->connection;
}
public function selectAllResults() {
$result = array();
$res = $this->lastResult;
if ($res == null) {
throw new Exception('No query result to fetch from!');
}
while (($row = mysql_fetch_assoc($res)) !== false) {
$result[] = $row;
}
return $result;
}
public function executeRawQuery($raw_query) {
$this->lastResult = null;
$retries = 3;
while ($retries--) {
try {
$this->requireConnection();
$start = microtime(true);
$profiler = PhutilServiceProfiler::getInstance();
$call_id = $profiler->beginServiceCall(
array(
- 'type' => 'query',
- 'query' => $raw_query,
+ 'type' => 'query',
+ 'config' => $this->configuration,
+ 'query' => $raw_query,
));
$result = @mysql_query($raw_query, $this->connection);
$profiler->endServiceCall($call_id, array());
if ($result) {
$this->lastResult = $result;
break;
}
$this->throwQueryException($this->connection);
} catch (AphrontQueryConnectionLostException $ex) {
if (!$retries) {
throw $ex;
}
if ($this->isInsideTransaction()) {
throw $ex;
}
$this->closeConnection();
}
}
}
private function throwQueryException($connection) {
$errno = mysql_errno($connection);
$error = mysql_error($connection);
switch ($errno) {
case 2013: // Connection Dropped
case 2006: // Gone Away
throw new AphrontQueryConnectionLostException("#{$errno}: {$error}");
case 1213: // Deadlock
case 1205: // Lock wait timeout exceeded
throw new AphrontQueryRecoverableException("#{$errno}: {$error}");
case 1062: // Duplicate Key
// NOTE: In some versions of MySQL we get a key name back here, but
// older versions just give us a key index ("key 2") so it's not
// portable to parse the key out of the error and attach it to the
// exception.
throw new AphrontQueryDuplicateKeyException("{$errno}: {$error}");
case 1044: // Access denied to database
case 1045: // Access denied (auth)
case 1142: // Access denied to table
case 1143: // Access denied to column
throw new AphrontQueryAccessDeniedException("#{$errno}: {$error}");
default:
// TODO: 1064 is syntax error, and quite terrible in production.
throw new AphrontQueryException("#{$errno}: {$error}");
}
}
}
diff --git a/src/view/page/standard/PhabricatorStandardPageView.php b/src/view/page/standard/PhabricatorStandardPageView.php
index e5dec0e373..b5abe90c11 100644
--- a/src/view/page/standard/PhabricatorStandardPageView.php
+++ b/src/view/page/standard/PhabricatorStandardPageView.php
@@ -1,348 +1,372 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorStandardPageView extends AphrontPageView {
private $baseURI;
private $applicationName;
private $tabs = array();
private $selectedTab;
private $glyph;
private $bodyContent;
private $request;
private $isAdminInterface;
private $showChrome = true;
+ private $isFrameable = false;
+ private $disableConsole;
public function setIsAdminInterface($is_admin_interface) {
$this->isAdminInterface = $is_admin_interface;
return $this;
}
public function getIsAdminInterface() {
return $this->isAdminInterface;
}
public function setRequest($request) {
$this->request = $request;
return $this;
}
public function getRequest() {
return $this->request;
}
public function setApplicationName($application_name) {
$this->applicationName = $application_name;
return $this;
}
+ public function setFrameable($frameable) {
+ $this->isFrameable = $frameable;
+ return $this;
+ }
+
+ public function setDisableConsole($disable) {
+ $this->disableConsole = $disable;
+ return $this;
+ }
+
public function getApplicationName() {
return $this->applicationName;
}
public function setBaseURI($base_uri) {
$this->baseURI = $base_uri;
return $this;
}
public function getBaseURI() {
return $this->baseURI;
}
public function setTabs(array $tabs, $selected_tab) {
$this->tabs = $tabs;
$this->selectedTab = $selected_tab;
return $this;
}
public function setShowChrome($show_chrome) {
$this->showChrome = $show_chrome;
return $this;
}
public function getShowChrome() {
return $this->showChrome;
}
public function getTitle() {
$use_glyph = true;
$request = $this->getRequest();
if ($request) {
$user = $request->getUser();
if ($user && $user->loadPreferences()->getPreference(
PhabricatorUserPreferences::PREFERENCE_TITLES) !== 'glyph') {
$use_glyph = false;
}
}
return ($use_glyph ?
$this->getGlyph() : '['.$this->getApplicationName().']').
' '.parent::getTitle();
}
protected function willRenderPage() {
if (!$this->getRequest()) {
throw new Exception(
"You must set the Request to render a PhabricatorStandardPageView.");
}
- $console = $this->getRequest()->getApplicationConfiguration()->getConsole();
+ $console = $this->getConsole();
require_celerity_resource('phabricator-core-css');
require_celerity_resource('phabricator-core-buttons-css');
require_celerity_resource('phabricator-standard-page-view');
Javelin::initBehavior('workflow', array());
Javelin::initBehavior(
'phabricator-keyboard-shortcuts',
array(
'helpURI' => '/help/keyboardshortcut/',
));
if ($console) {
require_celerity_resource('aphront-dark-console-css');
Javelin::initBehavior(
'dark-console',
array(
'uri' => '/~/',
));
// Change this to initBehavior when there is some behavior to initialize
require_celerity_resource('javelin-behavior-error-log');
}
$this->bodyContent = $this->renderChildren();
}
protected function getHead() {
+
+ $framebust = null;
+ if (!$this->isFrameable) {
+ $framebust = '(top != self) && top.location.replace(self.location.href);';
+ }
+
$response = CelerityAPI::getStaticResourceResponse();
$head =
'<script type="text/javascript">'.
- '(top != self) && top.location.replace(self.location.href);'.
+ $framebust.
'window.__DEV__=1;'.
'</script>'.
$response->renderResourcesOfType('css').
$response->renderSingleResource('javelin-magical-init');
$request = $this->getRequest();
if ($request) {
$user = $request->getUser();
if ($user) {
$monospaced = $user->loadPreferences()->getPreference(
PhabricatorUserPreferences::PREFERENCE_MONOSPACED
);
if (strlen($monospaced)) {
$head .=
'<style type="text/css">'.
'.PhabricatorMonospaced { font: '.
$monospaced.
' !important; }'.
'</style>';
}
}
}
return $head;
}
public function setGlyph($glyph) {
$this->glyph = $glyph;
return $this;
}
public function getGlyph() {
return $this->glyph;
}
protected function willSendResponse($response) {
$console = $this->getRequest()->getApplicationConfiguration()->getConsole();
if ($console) {
$response = str_replace(
'<darkconsole />',
$console->render($this->getRequest()),
$response);
}
return $response;
}
protected function getBody() {
- $console = $this->getRequest()->getApplicationConfiguration()->getConsole();
+ $console = $this->getConsole();
$tabs = array();
foreach ($this->tabs as $name => $tab) {
$tab_markup = phutil_render_tag(
'a',
array(
'href' => idx($tab, 'href'),
),
phutil_escape_html(idx($tab, 'name')));
$tab_markup = phutil_render_tag(
'td',
array(
'class' => ($name == $this->selectedTab)
? 'phabricator-selected-tab'
: null,
),
$tab_markup);
$tabs[] = $tab_markup;
}
$tabs = implode('', $tabs);
$login_stuff = null;
$request = $this->getRequest();
$user = null;
if ($request) {
$user = $request->getUser();
// NOTE: user may not be set here if we caught an exception early
// in the execution workflow.
if ($user && $user->getPHID()) {
$login_stuff =
phutil_render_tag(
'a',
array(
'href' => '/p/'.$user->getUsername().'/',
),
phutil_escape_html($user->getUsername())).
' · '.
'<a href="/settings/">Settings</a>'.
' · '.
phabricator_render_form(
$user,
array(
'action' => '/search/',
'method' => 'post',
'style' => 'display: inline',
),
'<input type="text" name="query" />'.
'<button>Search</button>');
}
}
$foot_links = array();
$version = PhabricatorEnv::getEnvConfig('phabricator.version');
$foot_links[] = phutil_escape_html('Phabricator '.$version);
if (PhabricatorEnv::getEnvConfig('darkconsole.enabled') &&
!PhabricatorEnv::getEnvConfig('darkconsole.always-on')) {
if ($console) {
$link = javelin_render_tag(
'a',
array(
'href' => '/~/',
'sigil' => 'workflow',
),
'Disable DarkConsole');
} else {
$link = javelin_render_tag(
'a',
array(
'href' => '/~/',
'sigil' => 'workflow',
),
'Enable DarkConsole');
}
$foot_links[] = $link;
}
if ($user && $user->getPHID()) {
// This ends up very early in tab order at the top of the page and there's
// a bunch of junk up there anyway, just shove it down here.
$foot_links[] = phabricator_render_form(
$user,
array(
'action' => '/logout/',
'method' => 'post',
'style' => 'display: inline',
),
'<button class="link">Logout</button>');
}
$foot_links = implode(' · ', $foot_links);
$admin_class = null;
if ($this->getIsAdminInterface()) {
$admin_class = 'phabricator-admin-page-view';
}
$header_chrome = null;
$footer_chrome = null;
if ($this->getShowChrome()) {
$header_chrome =
'<table class="phabricator-standard-header">'.
'<tr>'.
'<td class="phabricator-logo"><a href="/"> </a></td>'.
'<td>'.
'<table class="phabricator-primary-navigation">'.
'<tr>'.
'<th>'.
phutil_render_tag(
'a',
array(
'href' => $this->getBaseURI(),
'class' => 'phabricator-head-appname',
),
phutil_escape_html($this->getApplicationName())).
'</th>'.
$tabs.
'</tr>'.
'</table>'.
'</td>'.
'<td class="phabricator-login-details">'.
$login_stuff.
'</td>'.
'</tr>'.
'</table>';
$footer_chrome =
'<div class="phabricator-page-foot">'.
$foot_links.
'</div>';
}
return
($console ? '<darkconsole />' : null).
'<div class="phabricator-standard-page '.$admin_class.'">'.
$header_chrome.
$this->bodyContent.
'<div style="clear: both;"></div>'.
'</div>'.
$footer_chrome;
}
protected function getTail() {
$response = CelerityAPI::getStaticResourceResponse();
return
$response->renderResourcesOfType('js').
$response->renderHTMLFooter();
}
protected function getBodyClasses() {
$classes = array();
if (!$this->getShowChrome()) {
$classes[] = 'phabricator-chromeless-page';
}
return implode(' ', $classes);
}
+ private function getConsole() {
+ if ($this->disableConsole) {
+ return null;
+ }
+ return $this->getRequest()->getApplicationConfiguration()->getConsole();
+ }
}
diff --git a/webroot/rsrc/css/aphront/dark-console.css b/webroot/rsrc/css/aphront/dark-console.css
index 7fe3d766b5..6c7cda8baf 100644
--- a/webroot/rsrc/css/aphront/dark-console.css
+++ b/webroot/rsrc/css/aphront/dark-console.css
@@ -1,89 +1,154 @@
/**
* @provides aphront-dark-console-css
*/
.dark-console {
background: #555555;
color: #eeeeee;
width: 100%;
font-family: "Verdana";
font-size: 11px;
border-bottom: 2px solid #000000;
position: relative;
z-index: 1;
}
.dark-console-tabs {
width: 180px;
background: #222222;
border-right: 1px solid #888888;
padding: 2.5em 0em;
}
a.dark-console-tab {
padding: .75em 12px;
text-align: right;
background: #444444;
position: relative;
border: 1px solid #666666;
border-width: 1px 0;
border-right-color: #888888;
margin-bottom: 2px;
display: block;
color: #cccccc;
}
a.dark-console-tab-selected {
margin-right: -1px;
padding-right: 13px;
background: #555555;
border-color: #888888;
border-right-color: #555555;
color: #eeeeee;
}
.dark-console .aphront-table-view {
background: #888888;
color: #eeeeee;
margin: 1em 1%;
width: 98%;
border-color: #333333;
}
.dark-console .aphront-table-view th {
background: #333333;
color: #ffffff;
}
.dark-console .aphront-table-view td.header {
background: #444444;
color: #ffffff;
min-width: 200px;
}
.dark-console .aphront-table-view tr.alt {
background: #666666;
}
.dark-console .aphront-table-view tr.no-data td {
color: #dddddd;
}
.dark-console-panel-ErrorLog {
max-height: 500px;
overflow: auto;
}
.dark-console-panel-error-details {
display: none;
}
.dark-console-panel-error-separator {
background-color: #e8e8e8;
border-bottom: 1px solid #b7b7b7;
border-top: 1px solid #b7b7b7;
height: 2px;
}
+.explain-sev-1 {
+ color: #33ff33;
+}
+
+.explain-sev-2 {
+ color: #99ff33;
+}
+
+.explain-sev-3 {
+ color: #ccff33;
+}
+
+.explain-sev-4 {
+ color: #ffff33;
+}
+
+.explain-sev-5 {
+ color: #ffcc33;
+}
+
+.explain-sev-6 {
+ color: #ffffff;
+ font-weight: bold;
+ background: #aa0000;
+ padding: 0 1em;
+ border: 2px solid #ffff00;
+}
+
+.explain-sev-7 {
+ color: #aaaaaa;
+}
+
+.dark-console-panel-header {
+ background: #606060;
+ border-bottom: 1px solid #505050;
+ padding: .25em 1em .25em 0;
+}
+
+.dark-console-panel-header h1 {
+ padding: 1em;
+ font-size: 12px;
+ font-weight: normal;
+}
+
+.dark-console-panel-header .button {
+ margin-top: .5em;
+ float: right;
+}
+
+.dark-console-panel a.bright-link {
+ color: #00cfff;
+ font-weight: bold;
+}
+
+.dark-console iframe {
+ width: 98%;
+ margin: .5em 1%;
+ height: 450px;
+ border: 0;
+}
+
+.dark-console-no-content {
+ padding: 1.5em 2em;
+ font-style: italic;
+}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 19, 13:01 (3 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1124854
Default Alt Text
(85 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment