(stable) Promote 2016 Week 33
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
return array(
|
return array(
|
||||||
'names' => array(
|
'names' => array(
|
||||||
'core.pkg.css' => '90c46327',
|
'core.pkg.css' => '340c5b75',
|
||||||
'core.pkg.js' => 'b562c3db',
|
'core.pkg.js' => 'b562c3db',
|
||||||
'darkconsole.pkg.js' => 'e7393ebb',
|
'darkconsole.pkg.js' => 'e7393ebb',
|
||||||
'differential.pkg.css' => '3fb7f532',
|
'differential.pkg.css' => '3fb7f532',
|
||||||
|
@ -24,7 +24,7 @@ return array(
|
||||||
'rsrc/css/aphront/multi-column.css' => 'fd18389d',
|
'rsrc/css/aphront/multi-column.css' => 'fd18389d',
|
||||||
'rsrc/css/aphront/notification.css' => '3f6c89c9',
|
'rsrc/css/aphront/notification.css' => '3f6c89c9',
|
||||||
'rsrc/css/aphront/panel-view.css' => '8427b78d',
|
'rsrc/css/aphront/panel-view.css' => '8427b78d',
|
||||||
'rsrc/css/aphront/phabricator-nav-view.css' => '09f3d0db',
|
'rsrc/css/aphront/phabricator-nav-view.css' => 'b29426e9',
|
||||||
'rsrc/css/aphront/table-view.css' => '832656fd',
|
'rsrc/css/aphront/table-view.css' => '832656fd',
|
||||||
'rsrc/css/aphront/tokenizer.css' => '056da01b',
|
'rsrc/css/aphront/tokenizer.css' => '056da01b',
|
||||||
'rsrc/css/aphront/tooltip.css' => '1a07aea8',
|
'rsrc/css/aphront/tooltip.css' => '1a07aea8',
|
||||||
|
@ -32,7 +32,7 @@ return array(
|
||||||
'rsrc/css/aphront/typeahead.css' => 'd4f16145',
|
'rsrc/css/aphront/typeahead.css' => 'd4f16145',
|
||||||
'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af',
|
'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af',
|
||||||
'rsrc/css/application/auth/auth.css' => '0877ed6e',
|
'rsrc/css/application/auth/auth.css' => '0877ed6e',
|
||||||
'rsrc/css/application/base/main-menu-view.css' => 'b623169f',
|
'rsrc/css/application/base/main-menu-view.css' => '3b0d39f7',
|
||||||
'rsrc/css/application/base/notification-menu.css' => 'f31c0bde',
|
'rsrc/css/application/base/notification-menu.css' => 'f31c0bde',
|
||||||
'rsrc/css/application/base/phabricator-application-launch-view.css' => '95351601',
|
'rsrc/css/application/base/phabricator-application-launch-view.css' => '95351601',
|
||||||
'rsrc/css/application/base/phui-theme.css' => '027ba77e',
|
'rsrc/css/application/base/phui-theme.css' => '027ba77e',
|
||||||
|
@ -41,7 +41,7 @@ return array(
|
||||||
'rsrc/css/application/conduit/conduit-api.css' => '7bc725c4',
|
'rsrc/css/application/conduit/conduit-api.css' => '7bc725c4',
|
||||||
'rsrc/css/application/config/config-options.css' => '0ede4c9b',
|
'rsrc/css/application/config/config-options.css' => '0ede4c9b',
|
||||||
'rsrc/css/application/config/config-template.css' => '8e6c6fcd',
|
'rsrc/css/application/config/config-template.css' => '8e6c6fcd',
|
||||||
'rsrc/css/application/config/config-welcome.css' => '6abd79be',
|
'rsrc/css/application/config/config-welcome.css' => '035aa483',
|
||||||
'rsrc/css/application/config/setup-issue.css' => 'db7e9c40',
|
'rsrc/css/application/config/setup-issue.css' => 'db7e9c40',
|
||||||
'rsrc/css/application/config/unhandled-exception.css' => '4c96257a',
|
'rsrc/css/application/config/unhandled-exception.css' => '4c96257a',
|
||||||
'rsrc/css/application/conpherence/durable-column.css' => '86396117',
|
'rsrc/css/application/conpherence/durable-column.css' => '86396117',
|
||||||
|
@ -131,7 +131,7 @@ return array(
|
||||||
'rsrc/css/phui/phui-curtain-view.css' => '7148ae25',
|
'rsrc/css/phui/phui-curtain-view.css' => '7148ae25',
|
||||||
'rsrc/css/phui/phui-document-pro.css' => 'dc3d46ed',
|
'rsrc/css/phui/phui-document-pro.css' => 'dc3d46ed',
|
||||||
'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf',
|
'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf',
|
||||||
'rsrc/css/phui/phui-document.css' => '715aedfb',
|
'rsrc/css/phui/phui-document.css' => 'c32e8dec',
|
||||||
'rsrc/css/phui/phui-feed-story.css' => 'aa49845d',
|
'rsrc/css/phui/phui-feed-story.css' => 'aa49845d',
|
||||||
'rsrc/css/phui/phui-fontkit.css' => '9cda225e',
|
'rsrc/css/phui/phui-fontkit.css' => '9cda225e',
|
||||||
'rsrc/css/phui/phui-form-view.css' => 'fab0a10f',
|
'rsrc/css/phui/phui-form-view.css' => 'fab0a10f',
|
||||||
|
@ -163,7 +163,6 @@ return array(
|
||||||
'rsrc/css/phui/workboards/phui-workcard.css' => '0c62d7c5',
|
'rsrc/css/phui/workboards/phui-workcard.css' => '0c62d7c5',
|
||||||
'rsrc/css/phui/workboards/phui-workpanel.css' => '92197373',
|
'rsrc/css/phui/workboards/phui-workpanel.css' => '92197373',
|
||||||
'rsrc/css/sprite-login.css' => '60e8560e',
|
'rsrc/css/sprite-login.css' => '60e8560e',
|
||||||
'rsrc/css/sprite-menu.css' => '9dd65b92',
|
|
||||||
'rsrc/css/sprite-tokens.css' => '9cdfd599',
|
'rsrc/css/sprite-tokens.css' => '9cdfd599',
|
||||||
'rsrc/css/syntax/syntax-default.css' => '9923583c',
|
'rsrc/css/syntax/syntax-default.css' => '9923583c',
|
||||||
'rsrc/externals/d3/d3.min.js' => 'a11a5ff2',
|
'rsrc/externals/d3/d3.min.js' => 'a11a5ff2',
|
||||||
|
@ -320,6 +319,7 @@ return array(
|
||||||
'rsrc/image/icon/tango/upload.png' => '7bbb7984',
|
'rsrc/image/icon/tango/upload.png' => '7bbb7984',
|
||||||
'rsrc/image/icon/unsubscribe.png' => '25725013',
|
'rsrc/image/icon/unsubscribe.png' => '25725013',
|
||||||
'rsrc/image/lightblue-header.png' => '5c168b6d',
|
'rsrc/image/lightblue-header.png' => '5c168b6d',
|
||||||
|
'rsrc/image/logo/light-eye.png' => '1a576ddd',
|
||||||
'rsrc/image/main_texture.png' => '29a2c5ad',
|
'rsrc/image/main_texture.png' => '29a2c5ad',
|
||||||
'rsrc/image/menu_texture.png' => '5a17580d',
|
'rsrc/image/menu_texture.png' => '5a17580d',
|
||||||
'rsrc/image/people/harding.png' => '45aa614e',
|
'rsrc/image/people/harding.png' => '45aa614e',
|
||||||
|
@ -343,8 +343,6 @@ return array(
|
||||||
'rsrc/image/resize.png' => 'fd476de4',
|
'rsrc/image/resize.png' => 'fd476de4',
|
||||||
'rsrc/image/sprite-login-X2.png' => 'e3991e37',
|
'rsrc/image/sprite-login-X2.png' => 'e3991e37',
|
||||||
'rsrc/image/sprite-login.png' => '03d5af29',
|
'rsrc/image/sprite-login.png' => '03d5af29',
|
||||||
'rsrc/image/sprite-menu-X2.png' => 'cfd8fca5',
|
|
||||||
'rsrc/image/sprite-menu.png' => 'd7a99faa',
|
|
||||||
'rsrc/image/sprite-tokens-X2.png' => '804a5232',
|
'rsrc/image/sprite-tokens-X2.png' => '804a5232',
|
||||||
'rsrc/image/sprite-tokens.png' => 'b41d03da',
|
'rsrc/image/sprite-tokens.png' => 'b41d03da',
|
||||||
'rsrc/image/texture/card-gradient.png' => '815f26e8',
|
'rsrc/image/texture/card-gradient.png' => '815f26e8',
|
||||||
|
@ -548,7 +546,7 @@ return array(
|
||||||
'changeset-view-manager' => 'a2828756',
|
'changeset-view-manager' => 'a2828756',
|
||||||
'conduit-api-css' => '7bc725c4',
|
'conduit-api-css' => '7bc725c4',
|
||||||
'config-options-css' => '0ede4c9b',
|
'config-options-css' => '0ede4c9b',
|
||||||
'config-welcome-css' => '6abd79be',
|
'config-welcome-css' => '035aa483',
|
||||||
'conpherence-durable-column-view' => '86396117',
|
'conpherence-durable-column-view' => '86396117',
|
||||||
'conpherence-menu-css' => 'f99fee4c',
|
'conpherence-menu-css' => 'f99fee4c',
|
||||||
'conpherence-message-pane-css' => '5897d3ac',
|
'conpherence-message-pane-css' => '5897d3ac',
|
||||||
|
@ -785,8 +783,8 @@ return array(
|
||||||
'phabricator-flag-css' => '5337623f',
|
'phabricator-flag-css' => '5337623f',
|
||||||
'phabricator-keyboard-shortcut' => '1ae869f2',
|
'phabricator-keyboard-shortcut' => '1ae869f2',
|
||||||
'phabricator-keyboard-shortcut-manager' => '4a021c10',
|
'phabricator-keyboard-shortcut-manager' => '4a021c10',
|
||||||
'phabricator-main-menu-view' => 'b623169f',
|
'phabricator-main-menu-view' => '3b0d39f7',
|
||||||
'phabricator-nav-view-css' => '09f3d0db',
|
'phabricator-nav-view-css' => 'b29426e9',
|
||||||
'phabricator-notification' => 'ccf1cbf8',
|
'phabricator-notification' => 'ccf1cbf8',
|
||||||
'phabricator-notification-css' => '3f6c89c9',
|
'phabricator-notification-css' => '3f6c89c9',
|
||||||
'phabricator-notification-menu-css' => 'f31c0bde',
|
'phabricator-notification-menu-css' => 'f31c0bde',
|
||||||
|
@ -837,7 +835,7 @@ return array(
|
||||||
'phui-crumbs-view-css' => '9dac418c',
|
'phui-crumbs-view-css' => '9dac418c',
|
||||||
'phui-curtain-view-css' => '7148ae25',
|
'phui-curtain-view-css' => '7148ae25',
|
||||||
'phui-document-summary-view-css' => '9ca48bdf',
|
'phui-document-summary-view-css' => '9ca48bdf',
|
||||||
'phui-document-view-css' => '715aedfb',
|
'phui-document-view-css' => 'c32e8dec',
|
||||||
'phui-document-view-pro-css' => 'dc3d46ed',
|
'phui-document-view-pro-css' => 'dc3d46ed',
|
||||||
'phui-feed-story-css' => 'aa49845d',
|
'phui-feed-story-css' => 'aa49845d',
|
||||||
'phui-font-icon-base-css' => '6449bce8',
|
'phui-font-icon-base-css' => '6449bce8',
|
||||||
|
@ -891,7 +889,6 @@ return array(
|
||||||
'releeph-request-typeahead-css' => '667a48ae',
|
'releeph-request-typeahead-css' => '667a48ae',
|
||||||
'setup-issue-css' => 'db7e9c40',
|
'setup-issue-css' => 'db7e9c40',
|
||||||
'sprite-login-css' => '60e8560e',
|
'sprite-login-css' => '60e8560e',
|
||||||
'sprite-menu-css' => '9dd65b92',
|
|
||||||
'sprite-tokens-css' => '9cdfd599',
|
'sprite-tokens-css' => '9cdfd599',
|
||||||
'syntax-default-css' => '9923583c',
|
'syntax-default-css' => '9923583c',
|
||||||
'syntax-highlighting-css' => '769d3498',
|
'syntax-highlighting-css' => '769d3498',
|
||||||
|
@ -1165,6 +1162,9 @@ return array(
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
'javelin-magical-init',
|
'javelin-magical-init',
|
||||||
),
|
),
|
||||||
|
'3b0d39f7' => array(
|
||||||
|
'phui-theme-css',
|
||||||
|
),
|
||||||
'3cb0b2fc' => array(
|
'3cb0b2fc' => array(
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
|
@ -1844,9 +1844,6 @@ return array(
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
'javelin-util',
|
'javelin-util',
|
||||||
),
|
),
|
||||||
'b623169f' => array(
|
|
||||||
'phui-theme-css',
|
|
||||||
),
|
|
||||||
'b6993408' => array(
|
'b6993408' => array(
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
'javelin-stratcom',
|
'javelin-stratcom',
|
||||||
|
@ -2246,7 +2243,6 @@ return array(
|
||||||
'aphront-tooltip-css',
|
'aphront-tooltip-css',
|
||||||
'phabricator-flag-css',
|
'phabricator-flag-css',
|
||||||
'phui-info-view-css',
|
'phui-info-view-css',
|
||||||
'sprite-menu-css',
|
|
||||||
'phabricator-main-menu-view',
|
'phabricator-main-menu-view',
|
||||||
'phabricator-notification-css',
|
'phabricator-notification-css',
|
||||||
'phabricator-notification-menu-css',
|
'phabricator-notification-menu-css',
|
||||||
|
|
|
@ -104,7 +104,6 @@ return array(
|
||||||
'aphront-tooltip-css',
|
'aphront-tooltip-css',
|
||||||
'phabricator-flag-css',
|
'phabricator-flag-css',
|
||||||
'phui-info-view-css',
|
'phui-info-view-css',
|
||||||
'sprite-menu-css',
|
|
||||||
|
|
||||||
'phabricator-main-menu-view',
|
'phabricator-main-menu-view',
|
||||||
'phabricator-notification-css',
|
'phabricator-notification-css',
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"sprites": {
|
|
||||||
"dark-eye": {
|
|
||||||
"name": "dark-eye",
|
|
||||||
"rule": ".dark-eye",
|
|
||||||
"hash": "c8112e52666fa1cb509ebb2cdf3a3df5"
|
|
||||||
},
|
|
||||||
"dark-logo": {
|
|
||||||
"name": "dark-logo",
|
|
||||||
"rule": ".dark-logo",
|
|
||||||
"hash": "e3425da87e8f6737d8db0063d064cd7d"
|
|
||||||
},
|
|
||||||
"light-eye": {
|
|
||||||
"name": "light-eye",
|
|
||||||
"rule": ".light-eye",
|
|
||||||
"hash": "5b6bf7c8c10d4f7414d976f6e79ae2ff"
|
|
||||||
},
|
|
||||||
"light-logo": {
|
|
||||||
"name": "light-logo",
|
|
||||||
"rule": ".light-logo",
|
|
||||||
"hash": "bee37c0a86825ec7ded38936b1ba7b65"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"scales": [
|
|
||||||
1,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
"header": "\/**\n * @provides sprite-menu-css\n * @generated\n *\/\n\n.sprite-menu {\n background-image: url(\/rsrc\/image\/sprite-menu.png);\n background-repeat: no-repeat;\n}\n\n@media\nonly screen and (min-device-pixel-ratio: 1.5),\nonly screen and (-webkit-min-device-pixel-ratio: 1.5),\nonly screen and (min-resolution: 1.5dppx) {\n .sprite-menu {\n background-image: url(\/rsrc\/image\/sprite-menu-X2.png);\n background-size: {X}px {Y}px;\n }\n}\n",
|
|
||||||
"type": "standard"
|
|
||||||
}
|
|
Before Width: | Height: | Size: 2 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 1.7 KiB |
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_repository.repository_commit
|
||||||
|
CHANGE summary summary VARCHAR(255) NOT NULL COLLATE {$COLLATE_TEXT};
|
|
@ -27,7 +27,6 @@ $webroot = Filesystem::readablePath($webroot);
|
||||||
$generator = new CeleritySpriteGenerator();
|
$generator = new CeleritySpriteGenerator();
|
||||||
|
|
||||||
$sheets = array(
|
$sheets = array(
|
||||||
'menu' => $generator->buildMenuSheet(),
|
|
||||||
'tokens' => $generator->buildTokenSheet(),
|
'tokens' => $generator->buildTokenSheet(),
|
||||||
'login' => $generator->buildLoginSheet(),
|
'login' => $generator->buildLoginSheet(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1622,9 +1622,7 @@ phutil_register_library_map(array(
|
||||||
'PHUIDiffTableOfContentsItemView' => 'infrastructure/diff/view/PHUIDiffTableOfContentsItemView.php',
|
'PHUIDiffTableOfContentsItemView' => 'infrastructure/diff/view/PHUIDiffTableOfContentsItemView.php',
|
||||||
'PHUIDiffTableOfContentsListView' => 'infrastructure/diff/view/PHUIDiffTableOfContentsListView.php',
|
'PHUIDiffTableOfContentsListView' => 'infrastructure/diff/view/PHUIDiffTableOfContentsListView.php',
|
||||||
'PHUIDiffTwoUpInlineCommentRowScaffold' => 'infrastructure/diff/view/PHUIDiffTwoUpInlineCommentRowScaffold.php',
|
'PHUIDiffTwoUpInlineCommentRowScaffold' => 'infrastructure/diff/view/PHUIDiffTwoUpInlineCommentRowScaffold.php',
|
||||||
'PHUIDocumentExample' => 'applications/uiexample/examples/PHUIDocumentExample.php',
|
|
||||||
'PHUIDocumentSummaryView' => 'view/phui/PHUIDocumentSummaryView.php',
|
'PHUIDocumentSummaryView' => 'view/phui/PHUIDocumentSummaryView.php',
|
||||||
'PHUIDocumentView' => 'view/phui/PHUIDocumentView.php',
|
|
||||||
'PHUIDocumentViewPro' => 'view/phui/PHUIDocumentViewPro.php',
|
'PHUIDocumentViewPro' => 'view/phui/PHUIDocumentViewPro.php',
|
||||||
'PHUIFeedStoryExample' => 'applications/uiexample/examples/PHUIFeedStoryExample.php',
|
'PHUIFeedStoryExample' => 'applications/uiexample/examples/PHUIFeedStoryExample.php',
|
||||||
'PHUIFeedStoryView' => 'view/phui/PHUIFeedStoryView.php',
|
'PHUIFeedStoryView' => 'view/phui/PHUIFeedStoryView.php',
|
||||||
|
@ -2268,7 +2266,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCustomFieldStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStorage.php',
|
'PhabricatorCustomFieldStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStorage.php',
|
||||||
'PhabricatorCustomFieldStorageQuery' => 'infrastructure/customfield/query/PhabricatorCustomFieldStorageQuery.php',
|
'PhabricatorCustomFieldStorageQuery' => 'infrastructure/customfield/query/PhabricatorCustomFieldStorageQuery.php',
|
||||||
'PhabricatorCustomFieldStringIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStringIndexStorage.php',
|
'PhabricatorCustomFieldStringIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStringIndexStorage.php',
|
||||||
'PhabricatorCustomHeaderConfigType' => 'applications/config/custom/PhabricatorCustomHeaderConfigType.php',
|
'PhabricatorCustomLogoConfigType' => 'applications/config/custom/PhabricatorCustomLogoConfigType.php',
|
||||||
'PhabricatorDaemon' => 'infrastructure/daemon/PhabricatorDaemon.php',
|
'PhabricatorDaemon' => 'infrastructure/daemon/PhabricatorDaemon.php',
|
||||||
'PhabricatorDaemonBulkJobController' => 'applications/daemon/controller/PhabricatorDaemonBulkJobController.php',
|
'PhabricatorDaemonBulkJobController' => 'applications/daemon/controller/PhabricatorDaemonBulkJobController.php',
|
||||||
'PhabricatorDaemonBulkJobListController' => 'applications/daemon/controller/PhabricatorDaemonBulkJobListController.php',
|
'PhabricatorDaemonBulkJobListController' => 'applications/daemon/controller/PhabricatorDaemonBulkJobListController.php',
|
||||||
|
@ -3383,6 +3381,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRepositoryCommitPHIDType' => 'applications/repository/phid/PhabricatorRepositoryCommitPHIDType.php',
|
'PhabricatorRepositoryCommitPHIDType' => 'applications/repository/phid/PhabricatorRepositoryCommitPHIDType.php',
|
||||||
'PhabricatorRepositoryCommitParserWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitParserWorker.php',
|
'PhabricatorRepositoryCommitParserWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitParserWorker.php',
|
||||||
'PhabricatorRepositoryCommitRef' => 'applications/repository/engine/PhabricatorRepositoryCommitRef.php',
|
'PhabricatorRepositoryCommitRef' => 'applications/repository/engine/PhabricatorRepositoryCommitRef.php',
|
||||||
|
'PhabricatorRepositoryCommitTestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryCommitTestCase.php',
|
||||||
'PhabricatorRepositoryConfigOptions' => 'applications/repository/config/PhabricatorRepositoryConfigOptions.php',
|
'PhabricatorRepositoryConfigOptions' => 'applications/repository/config/PhabricatorRepositoryConfigOptions.php',
|
||||||
'PhabricatorRepositoryDAO' => 'applications/repository/storage/PhabricatorRepositoryDAO.php',
|
'PhabricatorRepositoryDAO' => 'applications/repository/storage/PhabricatorRepositoryDAO.php',
|
||||||
'PhabricatorRepositoryDiscoveryEngine' => 'applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php',
|
'PhabricatorRepositoryDiscoveryEngine' => 'applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php',
|
||||||
|
@ -6270,9 +6269,7 @@ phutil_register_library_map(array(
|
||||||
'PHUIDiffTableOfContentsItemView' => 'AphrontView',
|
'PHUIDiffTableOfContentsItemView' => 'AphrontView',
|
||||||
'PHUIDiffTableOfContentsListView' => 'AphrontView',
|
'PHUIDiffTableOfContentsListView' => 'AphrontView',
|
||||||
'PHUIDiffTwoUpInlineCommentRowScaffold' => 'PHUIDiffInlineCommentRowScaffold',
|
'PHUIDiffTwoUpInlineCommentRowScaffold' => 'PHUIDiffInlineCommentRowScaffold',
|
||||||
'PHUIDocumentExample' => 'PhabricatorUIExample',
|
|
||||||
'PHUIDocumentSummaryView' => 'AphrontTagView',
|
'PHUIDocumentSummaryView' => 'AphrontTagView',
|
||||||
'PHUIDocumentView' => 'AphrontTagView',
|
|
||||||
'PHUIDocumentViewPro' => 'AphrontTagView',
|
'PHUIDocumentViewPro' => 'AphrontTagView',
|
||||||
'PHUIFeedStoryExample' => 'PhabricatorUIExample',
|
'PHUIFeedStoryExample' => 'PhabricatorUIExample',
|
||||||
'PHUIFeedStoryView' => 'AphrontView',
|
'PHUIFeedStoryView' => 'AphrontView',
|
||||||
|
@ -7014,7 +7011,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCustomFieldStorage' => 'PhabricatorLiskDAO',
|
'PhabricatorCustomFieldStorage' => 'PhabricatorLiskDAO',
|
||||||
'PhabricatorCustomFieldStorageQuery' => 'Phobject',
|
'PhabricatorCustomFieldStorageQuery' => 'Phobject',
|
||||||
'PhabricatorCustomFieldStringIndexStorage' => 'PhabricatorCustomFieldIndexStorage',
|
'PhabricatorCustomFieldStringIndexStorage' => 'PhabricatorCustomFieldIndexStorage',
|
||||||
'PhabricatorCustomHeaderConfigType' => 'PhabricatorConfigOptionType',
|
'PhabricatorCustomLogoConfigType' => 'PhabricatorConfigOptionType',
|
||||||
'PhabricatorDaemon' => 'PhutilDaemon',
|
'PhabricatorDaemon' => 'PhutilDaemon',
|
||||||
'PhabricatorDaemonBulkJobController' => 'PhabricatorDaemonController',
|
'PhabricatorDaemonBulkJobController' => 'PhabricatorDaemonController',
|
||||||
'PhabricatorDaemonBulkJobListController' => 'PhabricatorDaemonBulkJobController',
|
'PhabricatorDaemonBulkJobListController' => 'PhabricatorDaemonBulkJobController',
|
||||||
|
@ -8342,6 +8339,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRepositoryCommitPHIDType' => 'PhabricatorPHIDType',
|
'PhabricatorRepositoryCommitPHIDType' => 'PhabricatorPHIDType',
|
||||||
'PhabricatorRepositoryCommitParserWorker' => 'PhabricatorWorker',
|
'PhabricatorRepositoryCommitParserWorker' => 'PhabricatorWorker',
|
||||||
'PhabricatorRepositoryCommitRef' => 'Phobject',
|
'PhabricatorRepositoryCommitRef' => 'Phobject',
|
||||||
|
'PhabricatorRepositoryCommitTestCase' => 'PhabricatorTestCase',
|
||||||
'PhabricatorRepositoryConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
'PhabricatorRepositoryConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||||
'PhabricatorRepositoryDAO' => 'PhabricatorLiskDAO',
|
'PhabricatorRepositoryDAO' => 'PhabricatorLiskDAO',
|
||||||
'PhabricatorRepositoryDiscoveryEngine' => 'PhabricatorRepositoryEngine',
|
'PhabricatorRepositoryDiscoveryEngine' => 'PhabricatorRepositoryEngine',
|
||||||
|
|
|
@ -28,6 +28,10 @@ final class PhabricatorCalendarApplication extends PhabricatorApplication {
|
||||||
return "\xE2\x8C\xA8";
|
return "\xE2\x8C\xA8";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getApplicationGroup() {
|
||||||
|
return self::GROUP_UTILITIES;
|
||||||
|
}
|
||||||
|
|
||||||
public function isPrototype() {
|
public function isPrototype() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,58 +2,6 @@
|
||||||
|
|
||||||
final class CeleritySpriteGenerator extends Phobject {
|
final class CeleritySpriteGenerator extends Phobject {
|
||||||
|
|
||||||
public function buildMenuSheet() {
|
|
||||||
$sprites = array();
|
|
||||||
|
|
||||||
$colors = array(
|
|
||||||
'dark',
|
|
||||||
'light',
|
|
||||||
);
|
|
||||||
|
|
||||||
$sources = array();
|
|
||||||
foreach ($colors as $color) {
|
|
||||||
$sources[$color.'-logo'] = array(
|
|
||||||
'x' => 96,
|
|
||||||
'y' => 40,
|
|
||||||
'css' => '.'.$color.'-logo',
|
|
||||||
);
|
|
||||||
$sources[$color.'-eye'] = array(
|
|
||||||
'x' => 40,
|
|
||||||
'y' => 40,
|
|
||||||
'css' => '.'.$color.'-eye',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$scales = array(
|
|
||||||
'1x' => 1,
|
|
||||||
'2x' => 2,
|
|
||||||
);
|
|
||||||
|
|
||||||
$template = new PhutilSprite();
|
|
||||||
foreach ($sources as $name => $spec) {
|
|
||||||
$sprite = id(clone $template)
|
|
||||||
->setName($name)
|
|
||||||
->setSourceSize($spec['x'], $spec['y'])
|
|
||||||
->setTargetCSS($spec['css']);
|
|
||||||
|
|
||||||
foreach ($scales as $scale_name => $scale) {
|
|
||||||
$path = 'menu_'.$scale_name.'/'.$name.'.png';
|
|
||||||
$path = $this->getPath($path);
|
|
||||||
|
|
||||||
$sprite->setSourceFile($path, $scale);
|
|
||||||
}
|
|
||||||
$sprites[] = $sprite;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sheet = $this->buildSheet('menu', true);
|
|
||||||
$sheet->setScales($scales);
|
|
||||||
foreach ($sprites as $sprite) {
|
|
||||||
$sheet->addSprite($sprite);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sheet;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function buildTokenSheet() {
|
public function buildTokenSheet() {
|
||||||
$icons = $this->getDirectoryList('tokens_1x');
|
$icons = $this->getDirectoryList('tokens_1x');
|
||||||
$scales = array(
|
$scales = array(
|
||||||
|
|
|
@ -328,6 +328,10 @@ final class PhabricatorExtraConfigSetupCheck extends PhabricatorSetupCheck {
|
||||||
|
|
||||||
'metamta.re-prefix' => $global_settings_reason,
|
'metamta.re-prefix' => $global_settings_reason,
|
||||||
'metamta.vary-subjects' => $global_settings_reason,
|
'metamta.vary-subjects' => $global_settings_reason,
|
||||||
|
|
||||||
|
'ui.custom-header' => pht(
|
||||||
|
'This option has been replaced with `ui.logo`, which provides more '.
|
||||||
|
'flexible configuration options.'),
|
||||||
);
|
);
|
||||||
|
|
||||||
return $ancient_config;
|
return $ancient_config;
|
||||||
|
|
|
@ -43,7 +43,6 @@ final class PhabricatorConfigClusterRepositoriesController
|
||||||
|
|
||||||
$all_repositories = id(new PhabricatorRepositoryQuery())
|
$all_repositories = id(new PhabricatorRepositoryQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withHosted(PhabricatorRepositoryQuery::HOSTED_PHABRICATOR)
|
|
||||||
->withTypes(
|
->withTypes(
|
||||||
array(
|
array(
|
||||||
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT,
|
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT,
|
||||||
|
|
|
@ -98,7 +98,8 @@ final class PhabricatorConfigEditController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$form = new AphrontFormView();
|
$form = id(new AphrontFormView())
|
||||||
|
->setEncType('multipart/form-data');
|
||||||
|
|
||||||
$error_view = null;
|
$error_view = null;
|
||||||
if ($errors) {
|
if ($errors) {
|
||||||
|
@ -144,9 +145,9 @@ final class PhabricatorConfigEditController
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($option->getHidden() || $option->getLocked()) {
|
if ($option->getHidden() || $option->getLocked()) {
|
||||||
$control = null;
|
$controls = array();
|
||||||
} else {
|
} else {
|
||||||
$control = $this->renderControl(
|
$controls = $this->renderControls(
|
||||||
$option,
|
$option,
|
||||||
$display_value,
|
$display_value,
|
||||||
$e_value);
|
$e_value);
|
||||||
|
@ -201,9 +202,9 @@ final class PhabricatorConfigEditController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$form
|
foreach ($controls as $control) {
|
||||||
->appendChild($control);
|
$form->appendControl($control);
|
||||||
|
}
|
||||||
|
|
||||||
if (!$option->getLocked()) {
|
if (!$option->getLocked()) {
|
||||||
$form->appendChild(
|
$form->appendChild(
|
||||||
|
@ -279,6 +280,10 @@ final class PhabricatorConfigEditController
|
||||||
$e_value = null;
|
$e_value = null;
|
||||||
$errors = array();
|
$errors = array();
|
||||||
|
|
||||||
|
if ($option->isCustomType()) {
|
||||||
|
$info = $option->getCustomObject()->readRequest($option, $request);
|
||||||
|
list($e_value, $errors, $set_value, $value) = $info;
|
||||||
|
} else {
|
||||||
$value = $request->getStr('value');
|
$value = $request->getStr('value');
|
||||||
if (!strlen($value)) {
|
if (!strlen($value)) {
|
||||||
$value = null;
|
$value = null;
|
||||||
|
@ -292,10 +297,6 @@ final class PhabricatorConfigEditController
|
||||||
return array($e_value, $errors, $value, $xaction);
|
return array($e_value, $errors, $value, $xaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($option->isCustomType()) {
|
|
||||||
$info = $option->getCustomObject()->readRequest($option, $request);
|
|
||||||
list($e_value, $errors, $set_value, $value) = $info;
|
|
||||||
} else {
|
|
||||||
$type = $option->getType();
|
$type = $option->getType();
|
||||||
$set_value = null;
|
$set_value = null;
|
||||||
|
|
||||||
|
@ -415,13 +416,13 @@ final class PhabricatorConfigEditController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function renderControl(
|
private function renderControls(
|
||||||
PhabricatorConfigOption $option,
|
PhabricatorConfigOption $option,
|
||||||
$display_value,
|
$display_value,
|
||||||
$e_value) {
|
$e_value) {
|
||||||
|
|
||||||
if ($option->isCustomType()) {
|
if ($option->isCustomType()) {
|
||||||
$control = $option->getCustomObject()->renderControl(
|
$controls = $option->getCustomObject()->renderControls(
|
||||||
$option,
|
$option,
|
||||||
$display_value,
|
$display_value,
|
||||||
$e_value);
|
$e_value);
|
||||||
|
@ -487,9 +488,11 @@ final class PhabricatorConfigEditController
|
||||||
->setError($e_value)
|
->setError($e_value)
|
||||||
->setValue($display_value)
|
->setValue($display_value)
|
||||||
->setName('value');
|
->setName('value');
|
||||||
|
|
||||||
|
$controls = array($control);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $control;
|
return $controls;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function renderExamples(PhabricatorConfigOption $option) {
|
private function renderExamples(PhabricatorConfigOption $option) {
|
||||||
|
|
|
@ -358,7 +358,7 @@ final class PhabricatorConfigWelcomeController
|
||||||
$quick_header = new PHUIRemarkupView(
|
$quick_header = new PHUIRemarkupView(
|
||||||
$viewer, pht('=Quick Start Guide'));
|
$viewer, pht('=Quick Start Guide'));
|
||||||
|
|
||||||
return id(new PHUIDocumentView())
|
$document = id(new PHUIDocumentViewPro())
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->setFluid(true)
|
->setFluid(true)
|
||||||
->appendChild($setup_header)
|
->appendChild($setup_header)
|
||||||
|
@ -367,6 +367,11 @@ final class PhabricatorConfigWelcomeController
|
||||||
->appendChild($explore)
|
->appendChild($explore)
|
||||||
->appendChild($quick_header)
|
->appendChild($quick_header)
|
||||||
->appendChild($quick);
|
->appendChild($quick);
|
||||||
|
|
||||||
|
return id(new PHUIBoxView())
|
||||||
|
->setBorder(true)
|
||||||
|
->appendChild($document)
|
||||||
|
->addClass('mlb');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function newItem(AphrontRequest $request, $icon, $content) {
|
private function newItem(AphrontRequest $request, $icon, $content) {
|
||||||
|
|
|
@ -31,6 +31,16 @@ abstract class PhabricatorConfigOptionType extends Phobject {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function renderControls(
|
||||||
|
PhabricatorConfigOption $option,
|
||||||
|
$display_value,
|
||||||
|
$e_value) {
|
||||||
|
|
||||||
|
$control = $this->renderControl($option, $display_value, $e_value);
|
||||||
|
|
||||||
|
return array($control);
|
||||||
|
}
|
||||||
|
|
||||||
public function renderControl(
|
public function renderControl(
|
||||||
PhabricatorConfigOption $option,
|
PhabricatorConfigOption $option,
|
||||||
$display_value,
|
$display_value,
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class PhabricatorCustomHeaderConfigType
|
|
||||||
extends PhabricatorConfigOptionType {
|
|
||||||
|
|
||||||
public function validateOption(PhabricatorConfigOption $option, $value) {
|
|
||||||
if (phid_get_type($value) != PhabricatorFileFilePHIDType::TYPECONST) {
|
|
||||||
throw new Exception(
|
|
||||||
pht(
|
|
||||||
'%s is not a valid file PHID.',
|
|
||||||
$value));
|
|
||||||
}
|
|
||||||
|
|
||||||
$file = id(new PhabricatorFileQuery())
|
|
||||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
|
||||||
->withPHIDs(array($value))
|
|
||||||
->executeOne();
|
|
||||||
if (!$file) {
|
|
||||||
throw new Exception(
|
|
||||||
pht(
|
|
||||||
'%s is not a valid file PHID.',
|
|
||||||
$value));
|
|
||||||
}
|
|
||||||
|
|
||||||
$most_open_policy = PhabricatorPolicies::getMostOpenPolicy();
|
|
||||||
if ($file->getViewPolicy() != $most_open_policy) {
|
|
||||||
throw new Exception(
|
|
||||||
pht(
|
|
||||||
'Specified file %s has policy "%s" but should have policy "%s".',
|
|
||||||
$value,
|
|
||||||
$file->getViewPolicy(),
|
|
||||||
$most_open_policy));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$file->isViewableImage()) {
|
|
||||||
throw new Exception(
|
|
||||||
pht(
|
|
||||||
'Specified file %s is not a viewable image.',
|
|
||||||
$value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getExampleConfig() {
|
|
||||||
$config = 'PHID-FILE-abcd1234abcd1234abcd';
|
|
||||||
return $config;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCustomLogoConfigType
|
||||||
|
extends PhabricatorConfigOptionType {
|
||||||
|
|
||||||
|
public static function getLogoImagePHID() {
|
||||||
|
$logo = PhabricatorEnv::getEnvConfig('ui.logo');
|
||||||
|
return idx($logo, 'logoImagePHID');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getLogoWordmark() {
|
||||||
|
$logo = PhabricatorEnv::getEnvConfig('ui.logo');
|
||||||
|
return idx($logo, 'wordmarkText');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateOption(PhabricatorConfigOption $option, $value) {
|
||||||
|
if (!is_array($value)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Logo configuration is not valid: value must be a dictionary.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
PhutilTypeSpec::checkMap(
|
||||||
|
$value,
|
||||||
|
array(
|
||||||
|
'logoImagePHID' => 'optional string|null',
|
||||||
|
'wordmarkText' => 'optional string|null',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function readRequest(
|
||||||
|
PhabricatorConfigOption $option,
|
||||||
|
AphrontRequest $request) {
|
||||||
|
|
||||||
|
$viewer = $request->getViewer();
|
||||||
|
$view_policy = PhabricatorPolicies::POLICY_PUBLIC;
|
||||||
|
|
||||||
|
if ($request->getBool('removeLogo')) {
|
||||||
|
$logo_image_phid = null;
|
||||||
|
} else if ($request->getFileExists('logoImage')) {
|
||||||
|
$logo_image = PhabricatorFile::newFromPHPUpload(
|
||||||
|
idx($_FILES, 'logoImage'),
|
||||||
|
array(
|
||||||
|
'name' => 'logo',
|
||||||
|
'authorPHID' => $viewer->getPHID(),
|
||||||
|
'viewPolicy' => $view_policy,
|
||||||
|
'canCDN' => true,
|
||||||
|
'isExplicitUpload' => true,
|
||||||
|
));
|
||||||
|
$logo_image_phid = $logo_image->getPHID();
|
||||||
|
} else {
|
||||||
|
$logo_image_phid = self::getLogoImagePHID();
|
||||||
|
}
|
||||||
|
|
||||||
|
$wordmark_text = $request->getStr('wordmarkText');
|
||||||
|
|
||||||
|
$value = array(
|
||||||
|
'logoImagePHID' => $logo_image_phid,
|
||||||
|
'wordmarkText' => $wordmark_text,
|
||||||
|
);
|
||||||
|
|
||||||
|
$errors = array();
|
||||||
|
$e_value = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->validateOption($option, $value);
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$e_value = pht('Invalid');
|
||||||
|
$errors[] = $ex->getMessage();
|
||||||
|
$value = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
return array($e_value, $errors, $value, phutil_json_encode($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderControls(
|
||||||
|
PhabricatorConfigOption $option,
|
||||||
|
$display_value,
|
||||||
|
$e_value) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
$value = phutil_json_decode($display_value);
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$value = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$logo_image_phid = idx($value, 'logoImagePHID');
|
||||||
|
$wordmark_text = idx($value, 'wordmarkText');
|
||||||
|
|
||||||
|
$controls = array();
|
||||||
|
|
||||||
|
// TODO: This should be a PHUIFormFileControl, but that currently only
|
||||||
|
// works in "workflow" forms. It isn't trivial to convert this form into
|
||||||
|
// a workflow form, nor is it trivial to make the newer control work
|
||||||
|
// in non-workflow forms.
|
||||||
|
$controls[] = id(new AphrontFormFileControl())
|
||||||
|
->setName('logoImage')
|
||||||
|
->setLabel(pht('Logo Image'));
|
||||||
|
|
||||||
|
if ($logo_image_phid) {
|
||||||
|
$controls[] = id(new AphrontFormCheckboxControl())
|
||||||
|
->addCheckbox(
|
||||||
|
'removeLogo',
|
||||||
|
1,
|
||||||
|
pht('Remove Custom Logo'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$controls[] = id(new AphrontFormTextControl())
|
||||||
|
->setName('wordmarkText')
|
||||||
|
->setLabel(pht('Wordmark'))
|
||||||
|
->setPlaceholder(pht('Phabricator'))
|
||||||
|
->setValue($wordmark_text);
|
||||||
|
|
||||||
|
return $controls;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -20,9 +20,6 @@ final class PhabricatorUIConfigOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getOptions() {
|
public function getOptions() {
|
||||||
$custom_header_example =
|
|
||||||
PhabricatorCustomHeaderConfigType::getExampleConfig();
|
|
||||||
$experimental_link = 'https://secure.phabricator.com/T4214';
|
|
||||||
$options = array(
|
$options = array(
|
||||||
'blindigo' => 'blindigo',
|
'blindigo' => 'blindigo',
|
||||||
'red' => 'red',
|
'red' => 'red',
|
||||||
|
@ -48,11 +45,24 @@ final class PhabricatorUIConfigOptions
|
||||||
]
|
]
|
||||||
EOJSON;
|
EOJSON;
|
||||||
|
|
||||||
|
$logo_type = 'custom:PhabricatorCustomLogoConfigType';
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
$this->newOption('ui.header-color', 'enum', 'blindigo')
|
$this->newOption('ui.header-color', 'enum', 'blindigo')
|
||||||
->setDescription(
|
->setDescription(
|
||||||
pht('Sets the default color scheme of Phabricator.'))
|
pht('Sets the default color scheme of Phabricator.'))
|
||||||
->setEnumOptions($options),
|
->setEnumOptions($options),
|
||||||
|
$this->newOption('ui.logo', $logo_type, array())
|
||||||
|
->setSummary(
|
||||||
|
pht('Customize the logo and wordmark text in the header.'))
|
||||||
|
->setDescription(
|
||||||
|
pht(
|
||||||
|
"Customize the logo image and text which appears in the main ".
|
||||||
|
"site header:\n\n".
|
||||||
|
" - **Logo Image**: Upload a new 80 x 80px image to replace the ".
|
||||||
|
"Phabricator logo in the site header.\n\n".
|
||||||
|
" - **Wordmark**: Choose new text to display next to the logo. ".
|
||||||
|
"By default, the header displays //Phabricator//.\n\n")),
|
||||||
$this->newOption('ui.footer-items', 'list<wild>', array())
|
$this->newOption('ui.footer-items', 'list<wild>', array())
|
||||||
->setSummary(
|
->setSummary(
|
||||||
pht(
|
pht(
|
||||||
|
@ -69,31 +79,6 @@ EOJSON;
|
||||||
" omit this if you just want a piece of text, like a copyright ".
|
" omit this if you just want a piece of text, like a copyright ".
|
||||||
" notice."))
|
" notice."))
|
||||||
->addExample($example, pht('Basic Example')),
|
->addExample($example, pht('Basic Example')),
|
||||||
$this->newOption(
|
|
||||||
'ui.custom-header',
|
|
||||||
'custom:PhabricatorCustomHeaderConfigType',
|
|
||||||
null)
|
|
||||||
->setSummary(
|
|
||||||
pht('Customize the Phabricator logo.'))
|
|
||||||
->setDescription(
|
|
||||||
pht('You can customize the Phabricator logo by specifying the '.
|
|
||||||
'phid for a viewable image you have uploaded to Phabricator '.
|
|
||||||
'via the [[ /file/ | Files application]]. This image should '.
|
|
||||||
'be:'."\n".
|
|
||||||
' - 192px X 80px; while not enforced, images with these '.
|
|
||||||
'dimensions will look best across devices.'."\n".
|
|
||||||
' - have view policy public if [[ '.
|
|
||||||
'/config/edit/policy.allow-public | `policy.allow-public`]] '.
|
|
||||||
'is true and otherwise view policy user; mismatches in these '.
|
|
||||||
'policy settings will result in a broken logo for some users.'.
|
|
||||||
"\n\n".
|
|
||||||
'You should restart Phabricator after updating this value '.
|
|
||||||
'to see this change take effect.'.
|
|
||||||
"\n\n".
|
|
||||||
'As this feature is experimental, please read [[ %s | T4214 ]] '.
|
|
||||||
'for up to date information.',
|
|
||||||
$experimental_link))
|
|
||||||
->addExample($custom_header_example, pht('Valid Config')),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,12 @@ abstract class PhabricatorConfigSchemaSpec extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
$details = $this->getDetailsForDataType($type);
|
$details = $this->getDetailsForDataType($type);
|
||||||
list($column_type, $charset, $collation, $nullable, $auto) = $details;
|
|
||||||
|
$column_type = $details['type'];
|
||||||
|
$charset = $details['charset'];
|
||||||
|
$collation = $details['collation'];
|
||||||
|
$nullable = $details['nullable'];
|
||||||
|
$auto = $details['auto'];
|
||||||
|
|
||||||
$column = $this->newColumn($name)
|
$column = $this->newColumn($name)
|
||||||
->setDataType($type)
|
->setDataType($type)
|
||||||
|
@ -182,11 +187,17 @@ abstract class PhabricatorConfigSchemaSpec extends Phobject {
|
||||||
->setName($name);
|
->setName($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getMaximumByteLengthForDataType($data_type) {
|
||||||
|
$info = $this->getDetailsForDataType($data_type);
|
||||||
|
return idx($info, 'bytes');
|
||||||
|
}
|
||||||
|
|
||||||
private function getDetailsForDataType($data_type) {
|
private function getDetailsForDataType($data_type) {
|
||||||
$column_type = null;
|
$column_type = null;
|
||||||
$charset = null;
|
$charset = null;
|
||||||
$collation = null;
|
$collation = null;
|
||||||
$auto = false;
|
$auto = false;
|
||||||
|
$bytes = null;
|
||||||
|
|
||||||
// If the type ends with "?", make the column nullable.
|
// If the type ends with "?", make the column nullable.
|
||||||
$nullable = false;
|
$nullable = false;
|
||||||
|
@ -211,7 +222,6 @@ abstract class PhabricatorConfigSchemaSpec extends Phobject {
|
||||||
'text255' => true,
|
'text255' => true,
|
||||||
'text160' => true,
|
'text160' => true,
|
||||||
'text128' => true,
|
'text128' => true,
|
||||||
'text80' => true,
|
|
||||||
'text64' => true,
|
'text64' => true,
|
||||||
'text40' => true,
|
'text40' => true,
|
||||||
'text32' => true,
|
'text32' => true,
|
||||||
|
@ -237,6 +247,10 @@ abstract class PhabricatorConfigSchemaSpec extends Phobject {
|
||||||
$type = $matches[1];
|
$type = $matches[1];
|
||||||
$size = idx($matches, 2);
|
$size = idx($matches, 2);
|
||||||
|
|
||||||
|
if ($size) {
|
||||||
|
$bytes = $size;
|
||||||
|
}
|
||||||
|
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
case 'text':
|
case 'text':
|
||||||
if ($is_binary) {
|
if ($is_binary) {
|
||||||
|
@ -363,7 +377,14 @@ abstract class PhabricatorConfigSchemaSpec extends Phobject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return array($column_type, $charset, $collation, $nullable, $auto);
|
return array(
|
||||||
|
'type' => $column_type,
|
||||||
|
'charset' => $charset,
|
||||||
|
'collation' => $collation,
|
||||||
|
'nullable' => $nullable,
|
||||||
|
'auto' => $auto,
|
||||||
|
'bytes' => $bytes,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -598,7 +598,7 @@ final class DiffusionRepositoryClusterEngine extends Phobject {
|
||||||
->setArgv($argv)
|
->setArgv($argv)
|
||||||
->setSudoAsDaemon(true)
|
->setSudoAsDaemon(true)
|
||||||
->setCredentialPHID($repository->getCredentialPHID())
|
->setCredentialPHID($repository->getCredentialPHID())
|
||||||
->setURI($repository->getRemoteURI())
|
->setURI($repository->getRemoteURIObject())
|
||||||
->newFuture();
|
->newFuture();
|
||||||
|
|
||||||
$future->setCWD($local_path);
|
$future->setCWD($local_path);
|
||||||
|
|
|
@ -18,6 +18,10 @@ final class PhabricatorFeedApplication extends PhabricatorApplication {
|
||||||
return 'fa-newspaper-o';
|
return 'fa-newspaper-o';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getApplicationGroup() {
|
||||||
|
return self::GROUP_UTILITIES;
|
||||||
|
}
|
||||||
|
|
||||||
public function canUninstall() {
|
public function canUninstall() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
final class HeraldRuleViewController extends HeraldController {
|
final class HeraldRuleViewController extends HeraldController {
|
||||||
|
|
||||||
|
public function shouldAllowPublic() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public function handleRequest(AphrontRequest $request) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$viewer = $request->getViewer();
|
$viewer = $request->getViewer();
|
||||||
$id = $request->getURIData('id');
|
$id = $request->getURIData('id');
|
||||||
|
|
|
@ -249,9 +249,13 @@ final class HeraldTranscriptController extends HeraldController {
|
||||||
foreach ($rule_xscripts as $rule_xscript) {
|
foreach ($rule_xscripts as $rule_xscript) {
|
||||||
$rule_id = $rule_xscript->getRuleID();
|
$rule_id = $rule_xscript->getRuleID();
|
||||||
|
|
||||||
|
$rule_monogram = pht('H%d', $rule_id);
|
||||||
|
$rule_uri = '/'.$rule_monogram;
|
||||||
|
|
||||||
$rule_item = id(new PHUIObjectItemView())
|
$rule_item = id(new PHUIObjectItemView())
|
||||||
->setObjectName(pht('H%d', $rule_id))
|
->setObjectName($rule_monogram)
|
||||||
->setHeader($rule_xscript->getRuleName());
|
->setHeader($rule_xscript->getRuleName())
|
||||||
|
->setHref($rule_uri);
|
||||||
|
|
||||||
if (!$rule_xscript->getResult()) {
|
if (!$rule_xscript->getResult()) {
|
||||||
$rule_item->setDisabled(true);
|
$rule_item->setDisabled(true);
|
||||||
|
|
|
@ -288,39 +288,40 @@ final class HeraldRule extends HeraldDAO
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPolicy($capability) {
|
public function getPolicy($capability) {
|
||||||
|
if ($capability == PhabricatorPolicyCapability::CAN_VIEW) {
|
||||||
|
return PhabricatorPolicies::getMostOpenPolicy();
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->isGlobalRule()) {
|
if ($this->isGlobalRule()) {
|
||||||
switch ($capability) {
|
|
||||||
case PhabricatorPolicyCapability::CAN_VIEW:
|
|
||||||
return PhabricatorPolicies::POLICY_USER;
|
|
||||||
case PhabricatorPolicyCapability::CAN_EDIT:
|
|
||||||
$app = 'PhabricatorHeraldApplication';
|
$app = 'PhabricatorHeraldApplication';
|
||||||
$herald = PhabricatorApplication::getByClass($app);
|
$herald = PhabricatorApplication::getByClass($app);
|
||||||
$global = HeraldManageGlobalRulesCapability::CAPABILITY;
|
$global = HeraldManageGlobalRulesCapability::CAPABILITY;
|
||||||
return $herald->getPolicy($global);
|
return $herald->getPolicy($global);
|
||||||
}
|
|
||||||
} else if ($this->isObjectRule()) {
|
} else if ($this->isObjectRule()) {
|
||||||
return $this->getTriggerObject()->getPolicy($capability);
|
return $this->getTriggerObject()->getPolicy($capability);
|
||||||
} else {
|
} else {
|
||||||
return PhabricatorPolicies::POLICY_NOONE;
|
return $this->getAuthorPHID();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||||
if ($this->isPersonalRule()) {
|
|
||||||
return ($viewer->getPHID() == $this->getAuthorPHID());
|
|
||||||
} else {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public function describeAutomaticCapability($capability) {
|
public function describeAutomaticCapability($capability) {
|
||||||
if ($this->isPersonalRule()) {
|
if ($capability == PhabricatorPolicyCapability::CAN_VIEW) {
|
||||||
return pht("A personal rule's owner can always view and edit it.");
|
return null;
|
||||||
} else if ($this->isObjectRule()) {
|
|
||||||
return pht('Object rules inherit the policies of their objects.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
if ($this->isGlobalRule()) {
|
||||||
|
return pht(
|
||||||
|
'Global Herald rules can be edited by users with the "Can Manage '.
|
||||||
|
'Global Rules" Herald application permission.');
|
||||||
|
} else if ($this->isObjectRule()) {
|
||||||
|
return pht('Object rules inherit the edit policies of their objects.');
|
||||||
|
} else {
|
||||||
|
return pht('A personal rule can only be edited by its owner.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,10 @@ final class PhabricatorPackagesApplication extends PhabricatorApplication {
|
||||||
return 'fa-gift';
|
return 'fa-gift';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getApplicationGroup() {
|
||||||
|
return self::GROUP_UTILITIES;
|
||||||
|
}
|
||||||
|
|
||||||
public function isPrototype() {
|
public function isPrototype() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,10 @@ final class PhabricatorPeopleApplication extends PhabricatorApplication {
|
||||||
return pht('Sort of a social utility.');
|
return pht('Sort of a social utility.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getApplicationGroup() {
|
||||||
|
return self::GROUP_UTILITIES;
|
||||||
|
}
|
||||||
|
|
||||||
public function canUninstall() {
|
public function canUninstall() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,10 @@ final class PhabricatorPhurlApplication extends PhabricatorApplication {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getApplicationGroup() {
|
||||||
|
return self::GROUP_UTILITIES;
|
||||||
|
}
|
||||||
|
|
||||||
public function getRemarkupRules() {
|
public function getRemarkupRules() {
|
||||||
return array(
|
return array(
|
||||||
new PhabricatorPhurlRemarkupRule(),
|
new PhabricatorPhurlRemarkupRule(),
|
||||||
|
|
|
@ -34,6 +34,10 @@ final class PhabricatorPonderApplication extends PhabricatorApplication {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getApplicationGroup() {
|
||||||
|
return self::GROUP_UTILITIES;
|
||||||
|
}
|
||||||
|
|
||||||
public function supportsEmailIntegration() {
|
public function supportsEmailIntegration() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,10 @@ final class PhabricatorReleephApplication extends PhabricatorApplication {
|
||||||
return 'fa-flag-checkered';
|
return 'fa-flag-checkered';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getApplicationGroup() {
|
||||||
|
return self::GROUP_UTILITIES;
|
||||||
|
}
|
||||||
|
|
||||||
public function isPrototype() {
|
public function isPrototype() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ final class PhabricatorRepositoryCommit
|
||||||
'mailKey' => 'bytes20',
|
'mailKey' => 'bytes20',
|
||||||
'authorPHID' => 'phid?',
|
'authorPHID' => 'phid?',
|
||||||
'auditStatus' => 'uint32',
|
'auditStatus' => 'uint32',
|
||||||
'summary' => 'text80',
|
'summary' => 'text255',
|
||||||
'importStatus' => 'uint32',
|
'importStatus' => 'uint32',
|
||||||
),
|
),
|
||||||
self::CONFIG_KEY_SCHEMA => array(
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
|
|
|
@ -2,12 +2,6 @@
|
||||||
|
|
||||||
final class PhabricatorRepositoryCommitData extends PhabricatorRepositoryDAO {
|
final class PhabricatorRepositoryCommitData extends PhabricatorRepositoryDAO {
|
||||||
|
|
||||||
/**
|
|
||||||
* NOTE: We denormalize this into the commit table; make sure the sizes
|
|
||||||
* match up.
|
|
||||||
*/
|
|
||||||
const SUMMARY_MAX_LENGTH = 80;
|
|
||||||
|
|
||||||
protected $commitID;
|
protected $commitID;
|
||||||
protected $authorName = '';
|
protected $authorName = '';
|
||||||
protected $commitMessage = '';
|
protected $commitMessage = '';
|
||||||
|
@ -38,10 +32,14 @@ final class PhabricatorRepositoryCommitData extends PhabricatorRepositoryDAO {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function summarizeCommitMessage($message) {
|
public static function summarizeCommitMessage($message) {
|
||||||
|
$max_bytes = id(new PhabricatorRepositoryCommit())
|
||||||
|
->getColumnMaximumByteLength('summary');
|
||||||
|
|
||||||
$summary = phutil_split_lines($message, $retain_endings = false);
|
$summary = phutil_split_lines($message, $retain_endings = false);
|
||||||
$summary = head($summary);
|
$summary = head($summary);
|
||||||
$summary = id(new PhutilUTF8StringTruncator())
|
$summary = id(new PhutilUTF8StringTruncator())
|
||||||
->setMaximumBytes(self::SUMMARY_MAX_LENGTH)
|
->setMaximumBytes($max_bytes)
|
||||||
|
->setMaximumGlyphs(80)
|
||||||
->truncateString($summary);
|
->truncateString($summary);
|
||||||
|
|
||||||
return $summary;
|
return $summary;
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorRepositoryCommitTestCase
|
||||||
|
extends PhabricatorTestCase {
|
||||||
|
|
||||||
|
public function testSummarizeCommits() {
|
||||||
|
// Cyrillic "zhe".
|
||||||
|
$zhe = "\xD0\xB6";
|
||||||
|
|
||||||
|
// Symbol "Snowman".
|
||||||
|
$snowman = "\xE2\x98\x83";
|
||||||
|
|
||||||
|
// Emoji "boar".
|
||||||
|
$boar = "\xF0\x9F\x90\x97";
|
||||||
|
|
||||||
|
// Proper unicode truncation is tested elsewhere, this is just making
|
||||||
|
// sure column length handling is sane.
|
||||||
|
|
||||||
|
$map = array(
|
||||||
|
'' => 0,
|
||||||
|
'a' => 1,
|
||||||
|
str_repeat('a', 81) => 82,
|
||||||
|
str_repeat('a', 255) => 82,
|
||||||
|
str_repeat('aa ', 30) => 80,
|
||||||
|
str_repeat($zhe, 300) => 161,
|
||||||
|
str_repeat($snowman, 300) => 240,
|
||||||
|
str_repeat($boar, 300) => 255,
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($map as $input => $expect) {
|
||||||
|
$actual = PhabricatorRepositoryCommitData::summarizeCommitMessage(
|
||||||
|
$input);
|
||||||
|
$this->assertEqual($expect, strlen($actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,199 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class PHUIDocumentExample extends PhabricatorUIExample {
|
|
||||||
|
|
||||||
public function getName() {
|
|
||||||
return pht('Document View');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDescription() {
|
|
||||||
return pht('Useful for areas of large content navigation');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function renderExample() {
|
|
||||||
$request = $this->getRequest();
|
|
||||||
$user = $request->getUser();
|
|
||||||
|
|
||||||
$action = id(new PHUIListItemView())
|
|
||||||
->setName(pht('Actions'))
|
|
||||||
->setType(PHUIListItemView::TYPE_LABEL);
|
|
||||||
|
|
||||||
$action1 = id(new PHUIListItemView())
|
|
||||||
->setName(pht('Edit Document'))
|
|
||||||
->setHref('#')
|
|
||||||
->setIcon('fa-edit')
|
|
||||||
->setType(PHUIListItemView::TYPE_LINK);
|
|
||||||
|
|
||||||
$action2 = id(new PHUIListItemView())
|
|
||||||
->setName(pht('Move Document'))
|
|
||||||
->setHref('#')
|
|
||||||
->setIcon('fa-arrows')
|
|
||||||
->setType(PHUIListItemView::TYPE_LINK);
|
|
||||||
|
|
||||||
$action3 = id(new PHUIListItemView())
|
|
||||||
->setName(pht('Delete Document'))
|
|
||||||
->setHref('#')
|
|
||||||
->setIcon('fa-times')
|
|
||||||
->setType(PHUIListItemView::TYPE_LINK);
|
|
||||||
|
|
||||||
$action4 = id(new PHUIListItemView())
|
|
||||||
->setName(pht('View History'))
|
|
||||||
->setHref('#')
|
|
||||||
->setIcon('fa-list')
|
|
||||||
->setType(PHUIListItemView::TYPE_LINK);
|
|
||||||
|
|
||||||
$action5 = id(new PHUIListItemView())
|
|
||||||
->setName(pht('Subscribe'))
|
|
||||||
->setHref('#')
|
|
||||||
->setIcon('fa-plus-circle')
|
|
||||||
->setType(PHUIListItemView::TYPE_LINK);
|
|
||||||
|
|
||||||
$divider = id(new PHUIListItemView())
|
|
||||||
->setType(PHUIListItemView::TYPE_DIVIDER);
|
|
||||||
|
|
||||||
$header = id(new PHUIHeaderView())
|
|
||||||
->setHeader(pht('Installation'));
|
|
||||||
|
|
||||||
$label1 = id(new PHUIListItemView())
|
|
||||||
->setName(pht('Getting Started'))
|
|
||||||
->setType(PHUIListItemView::TYPE_LABEL);
|
|
||||||
|
|
||||||
$label2 = id(new PHUIListItemView())
|
|
||||||
->setName(pht('Documentation'))
|
|
||||||
->setType(PHUIListItemView::TYPE_LABEL);
|
|
||||||
|
|
||||||
$item1 = id(new PHUIListItemView())
|
|
||||||
->setName(pht('Installation'))
|
|
||||||
->setHref('#')
|
|
||||||
->setType(PHUIListItemView::TYPE_LINK);
|
|
||||||
|
|
||||||
$item2 = id(new PHUIListItemView())
|
|
||||||
->setName(pht('Webserver Config'))
|
|
||||||
->setHref('#')
|
|
||||||
->setType(PHUIListItemView::TYPE_LINK);
|
|
||||||
|
|
||||||
$item3 = id(new PHUIListItemView())
|
|
||||||
->setName(pht('Adding Users'))
|
|
||||||
->setHref('#')
|
|
||||||
->setType(PHUIListItemView::TYPE_LINK);
|
|
||||||
|
|
||||||
$item4 = id(new PHUIListItemView())
|
|
||||||
->setName(pht('Debugging'))
|
|
||||||
->setHref('#')
|
|
||||||
->setType(PHUIListItemView::TYPE_LINK);
|
|
||||||
|
|
||||||
$sidenav = id(new PHUIListView())
|
|
||||||
->setType(PHUIListView::SIDENAV_LIST)
|
|
||||||
->addMenuItem($action)
|
|
||||||
->addMenuItem($action1)
|
|
||||||
->addMenuItem($action2)
|
|
||||||
->addMenuItem($action3)
|
|
||||||
->addMenuItem($action4)
|
|
||||||
->addMenuItem($action5)
|
|
||||||
->addMenuItem($divider)
|
|
||||||
->addMenuItem($label1)
|
|
||||||
->addMenuItem($item1)
|
|
||||||
->addMenuItem($item2)
|
|
||||||
->addMenuItem($item3)
|
|
||||||
->addMenuItem($item4)
|
|
||||||
->addMenuItem($label2)
|
|
||||||
->addMenuItem($item2)
|
|
||||||
->addMenuItem($item3)
|
|
||||||
->addMenuItem($item4)
|
|
||||||
->addMenuItem($item1);
|
|
||||||
|
|
||||||
$home = id(new PHUIListItemView())
|
|
||||||
->setIcon('fa-home')
|
|
||||||
->setHref('#')
|
|
||||||
->setType(PHUIListItemView::TYPE_ICON);
|
|
||||||
|
|
||||||
$item1 = id(new PHUIListItemView())
|
|
||||||
->setName(pht('Installation'))
|
|
||||||
->setHref('#')
|
|
||||||
->setSelected(true)
|
|
||||||
->setType(PHUIListItemView::TYPE_LINK);
|
|
||||||
|
|
||||||
$item2 = id(new PHUIListItemView())
|
|
||||||
->setName(pht('Webserver Config'))
|
|
||||||
->setHref('#')
|
|
||||||
->setType(PHUIListItemView::TYPE_LINK);
|
|
||||||
|
|
||||||
$item3 = id(new PHUIListItemView())
|
|
||||||
->setName(pht('Adding Users'))
|
|
||||||
->setHref('#')
|
|
||||||
->setType(PHUIListItemView::TYPE_LINK);
|
|
||||||
|
|
||||||
$item4 = id(new PHUIListItemView())
|
|
||||||
->setName(pht('Debugging'))
|
|
||||||
->setHref('#')
|
|
||||||
->setType(PHUIListItemView::TYPE_LINK);
|
|
||||||
|
|
||||||
$topnav = id(new PHUIListView())
|
|
||||||
->setType(PHUIListView::NAVBAR_LIST)
|
|
||||||
->addMenuItem($home)
|
|
||||||
->addMenuItem($item1)
|
|
||||||
->addMenuItem($item2)
|
|
||||||
->addMenuItem($item3)
|
|
||||||
->addMenuItem($item4);
|
|
||||||
|
|
||||||
$document = hsprintf(
|
|
||||||
'<p class="pl">Lorem ipsum dolor sit amet, consectetur adipisicing, '.
|
|
||||||
'sed do eiusmod tempor incididunt ut labore et dolore magna '.
|
|
||||||
'aliqua. Ut enim ad minim veniam, quis nostrud exercitation '.
|
|
||||||
'ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis '.
|
|
||||||
'aute irure dolor in reprehenderit in voluptate velit esse cillum '.
|
|
||||||
'dolore eu fugiat nulla pariatur. Excepteur sint occaecat '.
|
|
||||||
'cupidatat non proident, sunt in culpa qui officia deserunt '.
|
|
||||||
'mollit anim id est laborum.</p>'.
|
|
||||||
'<p class="plr pll plb">Lorem ipsum dolor sit amet, consectetur, '.
|
|
||||||
'sed do eiusmod tempor incididunt ut labore et dolore magna '.
|
|
||||||
'aliqua. Ut enim ad minim veniam, quis nostrud exercitation '.
|
|
||||||
'ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis '.
|
|
||||||
'aute irure dolor in reprehenderit in voluptate velit esse cillum '.
|
|
||||||
'dolore eu fugiat nulla pariatur. Excepteur sint occaecat '.
|
|
||||||
'cupidatat non proident, sunt in culpa qui officia deserunt '.
|
|
||||||
'mollit anim id est laborum.</p>'.
|
|
||||||
'<p class="plr pll plb">Lorem ipsum dolor sit amet, consectetur, '.
|
|
||||||
'sed do eiusmod tempor incididunt ut labore et dolore magna '.
|
|
||||||
'aliqua. Ut enim ad minim veniam, quis nostrud exercitation '.
|
|
||||||
'ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis '.
|
|
||||||
'aute irure dolor in reprehenderit in voluptate velit esse cillum '.
|
|
||||||
'dolore eu fugiat nulla pariatur. Excepteur sint occaecat '.
|
|
||||||
'cupidatat non proident, sunt in culpa qui officia deserunt '.
|
|
||||||
'mollit anim id est laborum.</p>'.
|
|
||||||
'<p class="plr pll plb">Lorem ipsum dolor sit amet, consectetur, '.
|
|
||||||
'sed do eiusmod tempor incididunt ut labore et dolore magna '.
|
|
||||||
'aliqua. Ut enim ad minim veniam, quis nostrud exercitation '.
|
|
||||||
'ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis '.
|
|
||||||
'aute irure dolor in reprehenderit in voluptate velit esse cillum '.
|
|
||||||
'dolore eu fugiat nulla pariatur. Excepteur sint occaecat '.
|
|
||||||
'cupidatat non proident, sunt in culpa qui officia deserunt '.
|
|
||||||
'mollit anim id est laborum.</p>'.
|
|
||||||
'<p class="plr pll plb">Lorem ipsum dolor sit amet, consectetur, '.
|
|
||||||
'sed do eiusmod tempor incididunt ut labore et dolore magna '.
|
|
||||||
'aliqua. Ut enim ad minim veniam, quis nostrud exercitation '.
|
|
||||||
'ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis '.
|
|
||||||
'aute irure dolor in reprehenderit in voluptate velit esse cillum '.
|
|
||||||
'dolore eu fugiat nulla pariatur. Excepteur sint occaecat '.
|
|
||||||
'cupidatat non proident, sunt in culpa qui officia deserunt '.
|
|
||||||
'mollit anim id est laborum.</p>'.
|
|
||||||
'<p class="plr pll plb">Lorem ipsum dolor sit amet, consectetur, '.
|
|
||||||
'sed do eiusmod tempor incididunt ut labore et dolore magna '.
|
|
||||||
'aliqua. Ut enim ad minim veniam, quis nostrud exercitation '.
|
|
||||||
'ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis '.
|
|
||||||
'aute irure dolor in reprehenderit in voluptate velit esse cillum '.
|
|
||||||
'dolore eu fugiat nulla pariatur. Excepteur sint occaecat '.
|
|
||||||
'cupidatat non proident, sunt in culpa qui officia deserunt '.
|
|
||||||
'mollit anim id est laborum.</p>');
|
|
||||||
|
|
||||||
$content = new PHUIDocumentView();
|
|
||||||
$content->setBook(pht('Book or Project Name'), pht('Article'));
|
|
||||||
$content->setHeader($header);
|
|
||||||
$content->setFluid(true);
|
|
||||||
$content->setTopNav($topnav);
|
|
||||||
$content->setSidenav($sidenav);
|
|
||||||
$content->appendChild($document);
|
|
||||||
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,96 +3,138 @@
|
||||||
|
|
||||||
Use Herald to get notified of changes you care about.
|
Use Herald to get notified of changes you care about.
|
||||||
|
|
||||||
= Overview =
|
Overview
|
||||||
|
========
|
||||||
|
|
||||||
Herald allows you to write processing rules that take effect when objects (such
|
Herald allows you to write rules which run automatically when objects (like
|
||||||
as Differential revisions and commits) are created or updated. For instance, you
|
tasks or commits) are created or updated. For instance, you might want to get
|
||||||
might want to get notified every time someone sends out a revision that affects
|
notified every time someone sends out a revision that affects some file you're
|
||||||
some file you're interested in, even if they didn't add you as a reviewer.
|
interested in, even if they didn't add you as a reviewer.
|
||||||
|
|
||||||
Herald is less useful for small organizations (where everyone will generally
|
One way to think about Herald is that it is a lot like the mail rules you can
|
||||||
know most of what's going on) but the usefulness of the application increases
|
set up in most email clients to organize mail based on "To", "Subject", etc.
|
||||||
as an organization scales. Once there is too much activity to keep track of it
|
|
||||||
all, Herald allows you to filter it down so you're only notified of things you
|
|
||||||
are interested in.
|
|
||||||
|
|
||||||
= Global and Personal Rules =
|
|
||||||
|
|
||||||
You can create two kinds of Herald rules, //global// and //personal//:
|
|
||||||
|
|
||||||
- **Personal Rules** are rules you own, but they can only affect you. Only
|
|
||||||
you can edit or delete personal rules, but their actions are limited to
|
|
||||||
adding you to CC, subscribing you, etc.
|
|
||||||
- **Global Rules** are rules everyone owns, and they can affect anything.
|
|
||||||
Anyone can edit or delete a global rule, and they can take any action,
|
|
||||||
including affecting projects and mailing lists.
|
|
||||||
|
|
||||||
The general idea is to prevent individuals from controlling rules that affect
|
|
||||||
shared resources, so if a rule needs to be updated it's not a big deal if the
|
|
||||||
person who created it is on vacation.
|
|
||||||
|
|
||||||
= Rules, Conditions and Actions =
|
|
||||||
|
|
||||||
The best way to think of Herald is as a system similar to the mail rules you can
|
|
||||||
set up in most email clients, to organize mail based on "To", "Subject", etc.
|
|
||||||
Herald works very similarly, but operates on Phabricator objects (like revisions
|
Herald works very similarly, but operates on Phabricator objects (like revisions
|
||||||
and commits) instead of emails.
|
and commits) instead of emails.
|
||||||
|
|
||||||
Every time an object is created or updated, Herald rules are run on it and
|
For example, you can write a personal rule like this which triggers on tasks:
|
||||||
the actions for any matching rules are taken.
|
|
||||||
|
|
||||||
To create a new Herald rule, choose which type of event you want to act on
|
> When [ all of ] these conditions are met:
|
||||||
(e.g., changes to Differential Revisions, or Commits), and then set a list of
|
> [ Title ][ contains ][ quasar ]
|
||||||
conditions. For example, you might add the condition `Author is alincoln
|
> Take these actions [ every time ] this rule matches:
|
||||||
(Abraham Lincoln)` to keep track of everything alincoln does. Finally, set
|
> [ Add me as a subscriber ]
|
||||||
a list of actions to take when the conditions match, like adding yourself to the
|
|
||||||
CC list.
|
|
||||||
|
|
||||||
Now you'll automatically be added to CC any time alincoln creates a revision,
|
This rule will automatically subscribe you to any newly created or updated
|
||||||
and can keep an eye on what he's up to.
|
tasks that contain "quasar" in the title.
|
||||||
|
|
||||||
= Available Actions =
|
Herald rules are often used to: notify users, add reviewers, initiate audits,
|
||||||
|
classify objects, block commits, enforce CLAs, and run builds.
|
||||||
|
|
||||||
Herald rules can take a number of actions. Note that some actions are only
|
|
||||||
available from Global rules, and others only from Personal rules. Additionally,
|
|
||||||
not every action is available for every object type (for instance, you can not
|
|
||||||
trigger an audit based on a Differential revision).
|
|
||||||
|
|
||||||
- **Add CC**: Add a user or mailing list to the CC list for the object. For
|
Working with Rules
|
||||||
personal rules, you can only add yourself.
|
==================
|
||||||
- **Remove CC**: Remove a user or mailing list from the CC list for the
|
|
||||||
object. For personal rules, you can only remove yourself.
|
|
||||||
- **Send an Email to**: Send one email, but don't subscribe to other updates.
|
|
||||||
For personal rules, you can only email yourself.
|
|
||||||
- **Trigger an Audit**: For commits, trigger an audit request for a project
|
|
||||||
or user. For personal rules, you can only trigger an audit request to
|
|
||||||
yourself.
|
|
||||||
- **Mark with flag**: Flag the object for later review. This action is only
|
|
||||||
available on personal rules. If an object already has a flag, this action
|
|
||||||
will not add another flag.
|
|
||||||
- **Do Nothing**: Don't do anything. This can be used to disable a rule
|
|
||||||
temporarily, or to create a rule for an "Another Herald rule" condition.
|
|
||||||
|
|
||||||
= Testing Rules =
|
To create new Herald rules, navigate to the {nav Herald} application and select
|
||||||
|
{nav Create Herald Rule}.
|
||||||
|
|
||||||
When you've created a rule, use the "Test Console" to test it out. Enter a
|
Next, you'll choose an event that you want to write a rule for: for example,
|
||||||
revision or commit and Herald will do a dry run against that object, showing
|
a rule for when commits are discovered or a rule for when tasks are created or
|
||||||
you which rules //would// match had it actually been updated. Dry runs executed
|
updated.
|
||||||
via the test console don't take any actions.
|
|
||||||
|
|
||||||
= Advanced Herald =
|
After selecting an event, choose the type of rule to create. See "Rule Types"
|
||||||
|
below for a more detailed discussion.
|
||||||
|
|
||||||
A few features in Herald are particularly complicated:
|
Name the rule and provide conditions and actions. When events occur, the rule
|
||||||
|
will be evaluated automatically. If the conditions pass, the actions will be
|
||||||
|
taken.
|
||||||
|
|
||||||
- **matches regexp pair**: for Differential revisions, you can set a condition
|
To test rules, use {nav Herald > Test Console}. See "Testing Rules" below
|
||||||
like "Any changed file content matches regexp pair...". This allows you to
|
for greater detail.
|
||||||
specify two regexes in JSON format. The first will be used to match the
|
|
||||||
filename of the changed file; the second will be used to match the content.
|
To review which rules did or did not trigger for a particular event (and why),
|
||||||
For example, if you want to match revisions which add or remove calls to
|
see {nav Herald > Transcripts}.
|
||||||
a "muffinize" function, //but only in JS files//, you can set the value
|
|
||||||
to `["/\\.js$/", "/muffinize/"]` or similar.
|
|
||||||
- **Another Herald rule**: you can create Herald rules which depend on other
|
Rule Types
|
||||||
rules. This can be useful if you need to express a more complicated predicate
|
==========
|
||||||
than "all" vs "any" allows, or have a common set of conditions which you want
|
|
||||||
to share between several rules. If a rule is only being used as a group of
|
You can create three kinds of Herald rules: personal rules, object rules, and
|
||||||
conditions, you can set the action to "Do Nothing".
|
global rules.
|
||||||
|
|
||||||
|
- **Personal Rules** are rules owned by an individual. They're often used
|
||||||
|
to keep people informed about changes they're interested in.
|
||||||
|
- **Object Rules** are rules associated with an object (like a repository
|
||||||
|
or project). These are similar to global rules.
|
||||||
|
- **Global Rules** are apply to all objects. They're often used to block
|
||||||
|
commits or run builds.
|
||||||
|
|
||||||
|
|
||||||
|
Rule Policies
|
||||||
|
=============
|
||||||
|
|
||||||
|
All Herald rules are always visible to all users.
|
||||||
|
|
||||||
|
The edit policy for a rule depends on what type of rule it is:
|
||||||
|
|
||||||
|
- Personal rules are owned by a particular user, and can only be created or
|
||||||
|
edited by that user.
|
||||||
|
- Object rules are associated with a particular object (like a repository),
|
||||||
|
and can only be created or edited by users who can edit that object. That
|
||||||
|
is, if you can edit a repository, you can also create object rules for it
|
||||||
|
and edit existing object rules.
|
||||||
|
- Global rules are administrative and can only be created or edited by users
|
||||||
|
with the **Can Manage Global Rules** Herald application permission.
|
||||||
|
|
||||||
|
When rules are about to evaluate, they may first perform some policy tests.
|
||||||
|
|
||||||
|
- Personal rules check if the owning user can see the object which the rule
|
||||||
|
is about to run on. If the user can not see the object, the rule does not
|
||||||
|
run. This prevents individuals from writing rules which give them access
|
||||||
|
to information they don't have permission to see.
|
||||||
|
- Object and global rules **bypass policies** and always execute. This makes
|
||||||
|
them very powerful, and is why the **Can Manage Global Rules** policy is
|
||||||
|
restricted by default.
|
||||||
|
|
||||||
|
|
||||||
|
Testing Rules
|
||||||
|
=============
|
||||||
|
|
||||||
|
When you've created a rule, use the {nav Herald > Test Console} to test it out.
|
||||||
|
|
||||||
|
Enter an object name (like `D123`, `rXYZabcdef`, or `T456`) and Herald will
|
||||||
|
execute a dry run against that object, showing you which rules //would// match
|
||||||
|
had it actually been updated. Dry runs executed via the test console don't take
|
||||||
|
any actions.
|
||||||
|
|
||||||
|
|
||||||
|
Advanced Herald
|
||||||
|
===============
|
||||||
|
|
||||||
|
A few features in Herald are particularly complicated or unintuitive.
|
||||||
|
|
||||||
|
Condition **matches regexp pair**: Some conditions allow you to select the
|
||||||
|
operator "matches regexp pair". For example, you can write a rule against
|
||||||
|
revisions like this one:
|
||||||
|
|
||||||
|
> When [ all of ] these conditions are met:
|
||||||
|
> [ Changed file content ][ matches regexp pair ][ ... ]
|
||||||
|
|
||||||
|
This condition allows you to specify two regexes in JSON format. The first will
|
||||||
|
be used to match the filename of the changed file; the second will be used to
|
||||||
|
match the content. You can use these together to express conditions like
|
||||||
|
"content in Javascript files".
|
||||||
|
|
||||||
|
For example, if you want to match revisions which add or remove calls to a
|
||||||
|
"muffinize" function, //but only in JS files//, you can set the value to
|
||||||
|
`["/\\.js$/", "/muffinize/"]` or similar. This condition is satisfied only
|
||||||
|
when the filename matches the first expression and the conent matches the
|
||||||
|
second expression.
|
||||||
|
|
||||||
|
**Another Herald rule**: you can create Herald rules which depend on other
|
||||||
|
rules.
|
||||||
|
|
||||||
|
This can be useful if you need to express a more complicated condition
|
||||||
|
than "all" vs "any" allows, or have a common set of conditions which you want
|
||||||
|
to share between several rules.
|
||||||
|
|
||||||
|
If a rule is only being used as a group of conditions, you can set the action
|
||||||
|
to "Do Nothing".
|
||||||
|
|
|
@ -11,7 +11,7 @@ abstract class PhabricatorDaemon extends PhutilDaemon {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function willSleep($duration) {
|
protected function willSleep($duration) {
|
||||||
LiskDAO::closeAllConnections();
|
LiskDAO::closeInactiveConnections(60);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,24 @@ abstract class PhabricatorDaemon extends PhutilDaemon {
|
||||||
return $command;
|
return $command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We may reach this method while already running as the daemon user: for
|
||||||
|
// example, active and passive synchronization of clustered repositories
|
||||||
|
// run the same commands through the same code, but as different users.
|
||||||
|
|
||||||
|
// By default, `sudo` won't let you sudo to yourself, so we can get into
|
||||||
|
// trouble if we're already running as the daemon user unless the host has
|
||||||
|
// been configured to let the daemon user run commands as itself.
|
||||||
|
|
||||||
|
// Since this is silly and more complicated than doing this check, don't
|
||||||
|
// use `sudo` if we're already running as the correct user.
|
||||||
|
if (function_exists('posix_getuid')) {
|
||||||
|
$uid = posix_getuid();
|
||||||
|
$info = posix_getpwuid($uid);
|
||||||
|
if ($info && $info['name'] == $user) {
|
||||||
|
return $command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get the absolute path so we're safe against the caller wiping out
|
// Get the absolute path so we're safe against the caller wiping out
|
||||||
// PATH.
|
// PATH.
|
||||||
$sudo = Filesystem::resolveBinary('sudo');
|
$sudo = Filesystem::resolveBinary('sudo');
|
||||||
|
|
|
@ -1621,10 +1621,55 @@ abstract class LiskDAO extends Phobject {
|
||||||
return (bool)self::$transactionIsolationLevel;
|
return (bool)self::$transactionIsolationLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function closeAllConnections() {
|
/**
|
||||||
self::$connections = array();
|
* Close any connections with no recent activity.
|
||||||
|
*
|
||||||
|
* Long-running processes can use this method to clean up connections which
|
||||||
|
* have not been used recently.
|
||||||
|
*
|
||||||
|
* @param int Close connections with no activity for this many seconds.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function closeInactiveConnections($idle_window) {
|
||||||
|
$connections = self::$connections;
|
||||||
|
|
||||||
|
$now = PhabricatorTime::getNow();
|
||||||
|
foreach ($connections as $key => $connection) {
|
||||||
|
$last_active = $connection->getLastActiveEpoch();
|
||||||
|
|
||||||
|
$idle_duration = ($now - $last_active);
|
||||||
|
if ($idle_duration <= $idle_window) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self::closeConnection($key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function closeAllConnections() {
|
||||||
|
$connections = self::$connections;
|
||||||
|
|
||||||
|
foreach ($connections as $key => $connection) {
|
||||||
|
self::closeConnection($key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function closeConnection($key) {
|
||||||
|
if (empty(self::$connections[$key])) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'No database connection with connection key "%s" exists!',
|
||||||
|
$key));
|
||||||
|
}
|
||||||
|
|
||||||
|
$connection = self::$connections[$key];
|
||||||
|
unset(self::$connections[$key]);
|
||||||
|
|
||||||
|
$connection->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( Utilities )---------------------------------------------------------- */
|
/* -( Utilities )---------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
@ -1831,7 +1876,6 @@ abstract class LiskDAO extends Phobject {
|
||||||
return $this->getConfigOption(self::CONFIG_BINARY);
|
return $this->getConfigOption(self::CONFIG_BINARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function getSchemaColumns() {
|
public function getSchemaColumns() {
|
||||||
$custom_map = $this->getConfigOption(self::CONFIG_COLUMN_SCHEMA);
|
$custom_map = $this->getConfigOption(self::CONFIG_COLUMN_SCHEMA);
|
||||||
if (!$custom_map) {
|
if (!$custom_map) {
|
||||||
|
@ -1953,4 +1997,21 @@ abstract class LiskDAO extends Phobject {
|
||||||
return $custom_map + $default_map;
|
return $custom_map + $default_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getColumnMaximumByteLength($column) {
|
||||||
|
$map = $this->getSchemaColumns();
|
||||||
|
|
||||||
|
if (!isset($map[$column])) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Object (of class "%s") does not have a column "%s".',
|
||||||
|
get_class($this),
|
||||||
|
$column));
|
||||||
|
}
|
||||||
|
|
||||||
|
$data_type = $map[$column];
|
||||||
|
|
||||||
|
return id(new PhabricatorStorageSchemaSpec())
|
||||||
|
->getMaximumByteLengthForDataType($data_type);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,16 +122,17 @@ abstract class PhabricatorLiskDAO extends LiskDAO {
|
||||||
}
|
}
|
||||||
|
|
||||||
$replica = PhabricatorDatabaseRef::getReplicaDatabaseRef();
|
$replica = PhabricatorDatabaseRef::getReplicaDatabaseRef();
|
||||||
if (!$replica) {
|
if ($replica) {
|
||||||
throw new Exception(
|
|
||||||
pht('No valid databases are configured!'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$connection = $replica->newApplicationConnection($database);
|
$connection = $replica->newApplicationConnection($database);
|
||||||
$connection->setReadOnly(true);
|
$connection->setReadOnly(true);
|
||||||
if ($replica->isReachable($connection)) {
|
if ($replica->isReachable($connection)) {
|
||||||
return $connection;
|
return $connection;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$master && !$replica) {
|
||||||
|
$this->raiseUnconfigured($database);
|
||||||
|
}
|
||||||
|
|
||||||
$this->raiseUnreachable($database);
|
$this->raiseUnreachable($database);
|
||||||
}
|
}
|
||||||
|
@ -153,10 +154,18 @@ abstract class PhabricatorLiskDAO extends LiskDAO {
|
||||||
$database));
|
$database));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function raiseUnconfigured($database) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Unable to establish a connection to any database host '.
|
||||||
|
'(while trying "%s"). No masters or replicas are configured.',
|
||||||
|
$database));
|
||||||
|
}
|
||||||
|
|
||||||
private function raiseUnreachable($database) {
|
private function raiseUnreachable($database) {
|
||||||
throw new PhabricatorClusterStrandedException(
|
throw new PhabricatorClusterStrandedException(
|
||||||
pht(
|
pht(
|
||||||
'Unable to establish a connection to ANY database host '.
|
'Unable to establish a connection to any database host '.
|
||||||
'(while trying "%s"). All masters and replicas are completely '.
|
'(while trying "%s"). All masters and replicas are completely '.
|
||||||
'unreachable.',
|
'unreachable.',
|
||||||
$database));
|
$database));
|
||||||
|
|
|
@ -31,7 +31,7 @@ final class PhabricatorStorageManagementShellWorkflow
|
||||||
}
|
}
|
||||||
|
|
||||||
return phutil_passthru(
|
return phutil_passthru(
|
||||||
'mysql --protocol=TCP --default-character-set=utf8 '.
|
'mysql --protocol=TCP --default-character-set=utf8mb4 '.
|
||||||
'-u %s %C -h %s %C',
|
'-u %s %C -h %s %C',
|
||||||
$api->getUser(),
|
$api->getUser(),
|
||||||
$flag_password,
|
$flag_password,
|
||||||
|
|
|
@ -297,11 +297,13 @@ final class PhabricatorMainMenuView extends AphrontView {
|
||||||
}
|
}
|
||||||
|
|
||||||
private function renderPhabricatorLogo() {
|
private function renderPhabricatorLogo() {
|
||||||
$style_logo = null;
|
$custom_header = PhabricatorCustomLogoConfigType::getLogoImagePHID();
|
||||||
$custom_header = PhabricatorEnv::getEnvConfig('ui.custom-header');
|
|
||||||
|
$logo_style = array();
|
||||||
if ($custom_header) {
|
if ($custom_header) {
|
||||||
$cache = PhabricatorCaches::getImmutableCache();
|
$cache = PhabricatorCaches::getImmutableCache();
|
||||||
$cache_key_logo = 'ui.custom-header.logo-phid.v1.'.$custom_header;
|
$cache_key_logo = 'ui.custom-header.logo-phid.v3.'.$custom_header;
|
||||||
|
|
||||||
$logo_uri = $cache->getKey($cache_key_logo);
|
$logo_uri = $cache->getKey($cache_key_logo);
|
||||||
if (!$logo_uri) {
|
if (!$logo_uri) {
|
||||||
$file = id(new PhabricatorFileQuery())
|
$file = id(new PhabricatorFileQuery())
|
||||||
|
@ -313,21 +315,32 @@ final class PhabricatorMainMenuView extends AphrontView {
|
||||||
$cache->setKey($cache_key_logo, $logo_uri);
|
$cache->setKey($cache_key_logo, $logo_uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($logo_uri) {
|
|
||||||
$style_logo =
|
$logo_style[] = 'background-size: 40px 40px;';
|
||||||
'background-size: 96px 40px; '.
|
$logo_style[] = 'background-position: 0 0;';
|
||||||
'background-position: 0px 0px; '.
|
$logo_style[] = 'background-image: url('.$logo_uri.')';
|
||||||
'background-image: url('.$logo_uri.');';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$color = PhabricatorEnv::getEnvConfig('ui.header-color');
|
$logo_node = phutil_tag(
|
||||||
if ($color == 'light') {
|
'span',
|
||||||
$color = 'dark';
|
array(
|
||||||
} else {
|
'class' => 'phabricator-main-menu-eye',
|
||||||
$color = 'light';
|
'style' => implode(' ', $logo_style),
|
||||||
|
));
|
||||||
|
|
||||||
|
|
||||||
|
$wordmark_text = PhabricatorCustomLogoConfigType::getLogoWordmark();
|
||||||
|
if (!strlen($wordmark_text)) {
|
||||||
|
$wordmark_text = pht('Phabricator');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$wordmark_node = phutil_tag(
|
||||||
|
'span',
|
||||||
|
array(
|
||||||
|
'class' => 'phabricator-wordmark',
|
||||||
|
),
|
||||||
|
$wordmark_text);
|
||||||
|
|
||||||
return phutil_tag(
|
return phutil_tag(
|
||||||
'a',
|
'a',
|
||||||
array(
|
array(
|
||||||
|
@ -341,19 +354,8 @@ final class PhabricatorMainMenuView extends AphrontView {
|
||||||
'aural' => true,
|
'aural' => true,
|
||||||
),
|
),
|
||||||
pht('Home')),
|
pht('Home')),
|
||||||
phutil_tag(
|
$logo_node,
|
||||||
'span',
|
$wordmark_node,
|
||||||
array(
|
|
||||||
'class' => 'sprite-menu phabricator-main-menu-eye '.$color.'-eye',
|
|
||||||
),
|
|
||||||
''),
|
|
||||||
phutil_tag(
|
|
||||||
'span',
|
|
||||||
array(
|
|
||||||
'class' => 'sprite-menu phabricator-main-menu-logo '.$color.'-logo',
|
|
||||||
'style' => $style_logo,
|
|
||||||
),
|
|
||||||
''),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,162 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class PHUIDocumentView extends AphrontTagView {
|
|
||||||
|
|
||||||
/* For mobile displays, where do you want the sidebar */
|
|
||||||
const NAV_BOTTOM = 'nav_bottom';
|
|
||||||
const NAV_TOP = 'nav_top';
|
|
||||||
|
|
||||||
private $offset;
|
|
||||||
private $header;
|
|
||||||
private $sidenav;
|
|
||||||
private $topnav;
|
|
||||||
private $crumbs;
|
|
||||||
private $bookname;
|
|
||||||
private $bookdescription;
|
|
||||||
private $mobileview;
|
|
||||||
private $fluid;
|
|
||||||
|
|
||||||
public function setOffset($offset) {
|
|
||||||
$this->offset = $offset;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setHeader(PHUIHeaderView $header) {
|
|
||||||
$header->setTall(true);
|
|
||||||
$this->header = $header;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setSideNav(PHUIListView $list, $display = self::NAV_BOTTOM) {
|
|
||||||
$list->setType(PHUIListView::SIDENAV_LIST);
|
|
||||||
$this->sidenav = $list;
|
|
||||||
$this->mobileview = $display;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setTopNav(PHUIListView $list) {
|
|
||||||
$list->setType(PHUIListView::NAVBAR_LIST);
|
|
||||||
$this->topnav = $list;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setCrumbs(PHUIListView $list) {
|
|
||||||
$this->crumbs = $list;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setBook($name, $description) {
|
|
||||||
$this->bookname = $name;
|
|
||||||
$this->bookdescription = $description;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setFluid($fluid) {
|
|
||||||
$this->fluid = $fluid;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getTagAttributes() {
|
|
||||||
$classes = array();
|
|
||||||
|
|
||||||
if ($this->offset) {
|
|
||||||
$classes[] = 'phui-document-offset';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->fluid) {
|
|
||||||
$classes[] = 'phui-document-fluid';
|
|
||||||
}
|
|
||||||
|
|
||||||
return array(
|
|
||||||
'class' => $classes,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getTagContent() {
|
|
||||||
require_celerity_resource('phui-document-view-css');
|
|
||||||
|
|
||||||
$classes = array();
|
|
||||||
$classes[] = 'phui-document-view';
|
|
||||||
if ($this->offset) {
|
|
||||||
$classes[] = 'phui-offset-view';
|
|
||||||
}
|
|
||||||
if ($this->sidenav) {
|
|
||||||
$classes[] = 'phui-sidenav-view';
|
|
||||||
}
|
|
||||||
|
|
||||||
$sidenav = null;
|
|
||||||
if ($this->sidenav) {
|
|
||||||
$sidenav = phutil_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => 'phui-document-sidenav',
|
|
||||||
),
|
|
||||||
$this->sidenav);
|
|
||||||
}
|
|
||||||
|
|
||||||
$book = null;
|
|
||||||
if ($this->bookname) {
|
|
||||||
$book = pht('%s (%s)', $this->bookname, $this->bookdescription);
|
|
||||||
}
|
|
||||||
|
|
||||||
$topnav = null;
|
|
||||||
if ($this->topnav) {
|
|
||||||
$topnav = phutil_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => 'phui-document-topnav',
|
|
||||||
),
|
|
||||||
$this->topnav);
|
|
||||||
}
|
|
||||||
|
|
||||||
$crumbs = null;
|
|
||||||
if ($this->crumbs) {
|
|
||||||
$crumbs = phutil_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => 'phui-document-crumbs',
|
|
||||||
),
|
|
||||||
$this->bookName);
|
|
||||||
}
|
|
||||||
|
|
||||||
$main_content = $this->renderChildren();
|
|
||||||
|
|
||||||
if ($book) {
|
|
||||||
$this->header->setSubheader($book);
|
|
||||||
}
|
|
||||||
$content_inner = phutil_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => 'phui-document-inner',
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
$this->header,
|
|
||||||
$topnav,
|
|
||||||
$main_content,
|
|
||||||
$crumbs,
|
|
||||||
));
|
|
||||||
|
|
||||||
if ($this->mobileview == self::NAV_BOTTOM) {
|
|
||||||
$order = array($content_inner, $sidenav);
|
|
||||||
} else {
|
|
||||||
$order = array($sidenav, $content_inner);
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = phutil_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => 'phui-document-content',
|
|
||||||
),
|
|
||||||
$order);
|
|
||||||
|
|
||||||
$view = phutil_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => implode(' ', $classes),
|
|
||||||
),
|
|
||||||
$content);
|
|
||||||
|
|
||||||
return $view;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -68,6 +68,12 @@
|
||||||
margin-left: 212px;
|
margin-left: 212px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.has-drag-nav ul.phui-list-view {
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.device-desktop .phui-navigation-shell .has-drag-nav .phabricator-nav-local {
|
.device-desktop .phui-navigation-shell .has-drag-nav .phabricator-nav-local {
|
||||||
width: 205px;
|
width: 205px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
|
@ -41,27 +41,20 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.phabricator-main-menu-brand {
|
.phabricator-main-menu-brand {
|
||||||
display: inline-block;
|
|
||||||
width: 148px;
|
|
||||||
height: 44px;
|
height: 44px;
|
||||||
float: left;
|
float: left;
|
||||||
margin-right: 4px;
|
margin-right: 6px;
|
||||||
padding-left: 6px;
|
padding-left: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phabricator-main-menu-logo {
|
|
||||||
position: absolute;
|
|
||||||
width: 96px;
|
|
||||||
height: 40px;
|
|
||||||
left: 52px;
|
|
||||||
top: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phabricator-main-menu-eye {
|
.phabricator-main-menu-eye {
|
||||||
position: absolute;
|
margin: 2px 0;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
top: 2px;
|
float: left;
|
||||||
|
display: block;
|
||||||
|
background-image: url(/rsrc/image/logo/light-eye.png);
|
||||||
|
background-size: 40px 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.device-desktop .phabricator-main-menu-brand:hover {
|
.device-desktop .phabricator-main-menu-brand:hover {
|
||||||
|
@ -69,6 +62,21 @@
|
||||||
cursor: hand;
|
cursor: hand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.device-phone .phabricator-wordmark {
|
||||||
|
max-width: 112px; /* iPhone 5 limitation */
|
||||||
|
}
|
||||||
|
|
||||||
|
.phabricator-wordmark {
|
||||||
|
float: left;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 18px;
|
||||||
|
margin: 9px 4px 9px 6px;
|
||||||
|
padding-right: 8px;
|
||||||
|
max-width: 175px;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
/* - Expand/Collapse Button ----------------------------------------------------
|
/* - Expand/Collapse Button ----------------------------------------------------
|
||||||
|
|
||||||
On phones, the menu switches to a vertical layout and uses a button to expand
|
On phones, the menu switches to a vertical layout and uses a button to expand
|
||||||
|
|
|
@ -19,5 +19,10 @@
|
||||||
width: 32px;
|
width: 32px;
|
||||||
float: left;
|
float: left;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-left: 16px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.phui-document-view-pro .phui-document-content .config-welcome-box
|
||||||
|
.phabricator-remarkup {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
|
@ -8,15 +8,6 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phui-document-view .phui-header-shell {
|
|
||||||
padding: 16px;
|
|
||||||
background-color: {$bluebackground};
|
|
||||||
}
|
|
||||||
|
|
||||||
.phui-document-content {
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.device-desktop .phui-document-view {
|
.device-desktop .phui-document-view {
|
||||||
border: 1px solid {$lightblueborder};
|
border: 1px solid {$lightblueborder};
|
||||||
max-width: 960px;
|
max-width: 960px;
|
||||||
|
@ -33,44 +24,11 @@
|
||||||
margin: 16px;
|
margin: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phui-crumbs-view + .phui-document-fluid .phui-document-view {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.device-desktop .phui-document-view.phui-offset-view {
|
|
||||||
max-width: 800px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fix so that Phriction Document preview is the same width as the document */
|
/* Fix so that Phriction Document preview is the same width as the document */
|
||||||
.device-desktop .phui-remarkup-preview .phui-document-view {
|
.device-desktop .phui-remarkup-preview .phui-document-view {
|
||||||
width: 800px;
|
width: 800px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phui-document-sidenav {
|
|
||||||
position:absolute;
|
|
||||||
width: 200px;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.device-phone .phui-document-sidenav {
|
|
||||||
position: static;
|
|
||||||
width: auto;
|
|
||||||
border-top: 1px solid {$thinblueborder};
|
|
||||||
border-bottom: 1px solid {$thinblueborder};
|
|
||||||
}
|
|
||||||
|
|
||||||
.device-phone .phui-sidenav-view .phui-document-inner {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phui-sidenav-view .phui-document-inner {
|
|
||||||
margin-right: 200px;
|
|
||||||
border-right: 1px solid {$thinblueborder};
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phui-document-content .phui-header-shell {
|
.phui-document-content .phui-header-shell {
|
||||||
border-top: none;
|
border-top: none;
|
||||||
border-bottom: 1px solid {$lightblueborder};
|
border-bottom: 1px solid {$lightblueborder};
|
||||||
|
@ -88,11 +46,6 @@
|
||||||
padding: 8px 0 4px;
|
padding: 8px 0 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phui-document-content .phui-property-list-container {
|
|
||||||
border-bottom: 1px solid {$thinblueborder};
|
|
||||||
background-color: {$lightgreybackground};
|
|
||||||
}
|
|
||||||
|
|
||||||
.legalpad .phui-document-content .phui-property-list-view {
|
.legalpad .phui-document-content .phui-property-list-view {
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
@ -127,18 +80,10 @@
|
||||||
margin: 16px 0;
|
margin: 16px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.device-desktop .phui-document-offset {
|
|
||||||
padding-right: 120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phui-document-view .phui-info-severity-nodata {
|
.phui-document-view .phui-info-severity-nodata {
|
||||||
background-color: {$lightgreybackground};
|
background-color: {$lightgreybackground};
|
||||||
}
|
}
|
||||||
|
|
||||||
body .phui-document-view .phui-header-shell.phui-bleed-header {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phui-document-view .phui-property-list-section-header {
|
.phui-document-view .phui-property-list-section-header {
|
||||||
padding: 20px 24px 0px;
|
padding: 20px 24px 0px;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
/**
|
|
||||||
* @provides sprite-menu-css
|
|
||||||
* @generated
|
|
||||||
*/
|
|
||||||
|
|
||||||
.sprite-menu {
|
|
||||||
background-image: url(/rsrc/image/sprite-menu.png);
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media
|
|
||||||
only screen and (min-device-pixel-ratio: 1.5),
|
|
||||||
only screen and (-webkit-min-device-pixel-ratio: 1.5),
|
|
||||||
only screen and (min-resolution: 1.5dppx) {
|
|
||||||
.sprite-menu {
|
|
||||||
background-image: url(/rsrc/image/sprite-menu-X2.png);
|
|
||||||
background-size: 97px 123px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.dark-logo {
|
|
||||||
background-position: 0px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark-eye {
|
|
||||||
background-position: 0px -82px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.light-logo {
|
|
||||||
background-position: 0px -41px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.light-eye {
|
|
||||||
background-position: -41px -82px;
|
|
||||||
}
|
|
BIN
webroot/rsrc/image/logo/light-eye.png
Normal file
After Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 2.1 KiB |