(stable) Promote 2016 Week 33
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
return array(
|
||||
'names' => array(
|
||||
'core.pkg.css' => '90c46327',
|
||||
'core.pkg.css' => '340c5b75',
|
||||
'core.pkg.js' => 'b562c3db',
|
||||
'darkconsole.pkg.js' => 'e7393ebb',
|
||||
'differential.pkg.css' => '3fb7f532',
|
||||
|
@ -24,7 +24,7 @@ return array(
|
|||
'rsrc/css/aphront/multi-column.css' => 'fd18389d',
|
||||
'rsrc/css/aphront/notification.css' => '3f6c89c9',
|
||||
'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/tokenizer.css' => '056da01b',
|
||||
'rsrc/css/aphront/tooltip.css' => '1a07aea8',
|
||||
|
@ -32,7 +32,7 @@ return array(
|
|||
'rsrc/css/aphront/typeahead.css' => 'd4f16145',
|
||||
'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af',
|
||||
'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/phabricator-application-launch-view.css' => '95351601',
|
||||
'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/config/config-options.css' => '0ede4c9b',
|
||||
'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/unhandled-exception.css' => '4c96257a',
|
||||
'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-document-pro.css' => 'dc3d46ed',
|
||||
'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-fontkit.css' => '9cda225e',
|
||||
'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-workpanel.css' => '92197373',
|
||||
'rsrc/css/sprite-login.css' => '60e8560e',
|
||||
'rsrc/css/sprite-menu.css' => '9dd65b92',
|
||||
'rsrc/css/sprite-tokens.css' => '9cdfd599',
|
||||
'rsrc/css/syntax/syntax-default.css' => '9923583c',
|
||||
'rsrc/externals/d3/d3.min.js' => 'a11a5ff2',
|
||||
|
@ -320,6 +319,7 @@ return array(
|
|||
'rsrc/image/icon/tango/upload.png' => '7bbb7984',
|
||||
'rsrc/image/icon/unsubscribe.png' => '25725013',
|
||||
'rsrc/image/lightblue-header.png' => '5c168b6d',
|
||||
'rsrc/image/logo/light-eye.png' => '1a576ddd',
|
||||
'rsrc/image/main_texture.png' => '29a2c5ad',
|
||||
'rsrc/image/menu_texture.png' => '5a17580d',
|
||||
'rsrc/image/people/harding.png' => '45aa614e',
|
||||
|
@ -343,8 +343,6 @@ return array(
|
|||
'rsrc/image/resize.png' => 'fd476de4',
|
||||
'rsrc/image/sprite-login-X2.png' => 'e3991e37',
|
||||
'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.png' => 'b41d03da',
|
||||
'rsrc/image/texture/card-gradient.png' => '815f26e8',
|
||||
|
@ -548,7 +546,7 @@ return array(
|
|||
'changeset-view-manager' => 'a2828756',
|
||||
'conduit-api-css' => '7bc725c4',
|
||||
'config-options-css' => '0ede4c9b',
|
||||
'config-welcome-css' => '6abd79be',
|
||||
'config-welcome-css' => '035aa483',
|
||||
'conpherence-durable-column-view' => '86396117',
|
||||
'conpherence-menu-css' => 'f99fee4c',
|
||||
'conpherence-message-pane-css' => '5897d3ac',
|
||||
|
@ -785,8 +783,8 @@ return array(
|
|||
'phabricator-flag-css' => '5337623f',
|
||||
'phabricator-keyboard-shortcut' => '1ae869f2',
|
||||
'phabricator-keyboard-shortcut-manager' => '4a021c10',
|
||||
'phabricator-main-menu-view' => 'b623169f',
|
||||
'phabricator-nav-view-css' => '09f3d0db',
|
||||
'phabricator-main-menu-view' => '3b0d39f7',
|
||||
'phabricator-nav-view-css' => 'b29426e9',
|
||||
'phabricator-notification' => 'ccf1cbf8',
|
||||
'phabricator-notification-css' => '3f6c89c9',
|
||||
'phabricator-notification-menu-css' => 'f31c0bde',
|
||||
|
@ -837,7 +835,7 @@ return array(
|
|||
'phui-crumbs-view-css' => '9dac418c',
|
||||
'phui-curtain-view-css' => '7148ae25',
|
||||
'phui-document-summary-view-css' => '9ca48bdf',
|
||||
'phui-document-view-css' => '715aedfb',
|
||||
'phui-document-view-css' => 'c32e8dec',
|
||||
'phui-document-view-pro-css' => 'dc3d46ed',
|
||||
'phui-feed-story-css' => 'aa49845d',
|
||||
'phui-font-icon-base-css' => '6449bce8',
|
||||
|
@ -891,7 +889,6 @@ return array(
|
|||
'releeph-request-typeahead-css' => '667a48ae',
|
||||
'setup-issue-css' => 'db7e9c40',
|
||||
'sprite-login-css' => '60e8560e',
|
||||
'sprite-menu-css' => '9dd65b92',
|
||||
'sprite-tokens-css' => '9cdfd599',
|
||||
'syntax-default-css' => '9923583c',
|
||||
'syntax-highlighting-css' => '769d3498',
|
||||
|
@ -1165,6 +1162,9 @@ return array(
|
|||
'javelin-dom',
|
||||
'javelin-magical-init',
|
||||
),
|
||||
'3b0d39f7' => array(
|
||||
'phui-theme-css',
|
||||
),
|
||||
'3cb0b2fc' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1844,9 +1844,6 @@ return array(
|
|||
'javelin-dom',
|
||||
'javelin-util',
|
||||
),
|
||||
'b623169f' => array(
|
||||
'phui-theme-css',
|
||||
),
|
||||
'b6993408' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
@ -2246,7 +2243,6 @@ return array(
|
|||
'aphront-tooltip-css',
|
||||
'phabricator-flag-css',
|
||||
'phui-info-view-css',
|
||||
'sprite-menu-css',
|
||||
'phabricator-main-menu-view',
|
||||
'phabricator-notification-css',
|
||||
'phabricator-notification-menu-css',
|
||||
|
|
|
@ -104,7 +104,6 @@ return array(
|
|||
'aphront-tooltip-css',
|
||||
'phabricator-flag-css',
|
||||
'phui-info-view-css',
|
||||
'sprite-menu-css',
|
||||
|
||||
'phabricator-main-menu-view',
|
||||
'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();
|
||||
|
||||
$sheets = array(
|
||||
'menu' => $generator->buildMenuSheet(),
|
||||
'tokens' => $generator->buildTokenSheet(),
|
||||
'login' => $generator->buildLoginSheet(),
|
||||
);
|
||||
|
|
|
@ -1622,9 +1622,7 @@ phutil_register_library_map(array(
|
|||
'PHUIDiffTableOfContentsItemView' => 'infrastructure/diff/view/PHUIDiffTableOfContentsItemView.php',
|
||||
'PHUIDiffTableOfContentsListView' => 'infrastructure/diff/view/PHUIDiffTableOfContentsListView.php',
|
||||
'PHUIDiffTwoUpInlineCommentRowScaffold' => 'infrastructure/diff/view/PHUIDiffTwoUpInlineCommentRowScaffold.php',
|
||||
'PHUIDocumentExample' => 'applications/uiexample/examples/PHUIDocumentExample.php',
|
||||
'PHUIDocumentSummaryView' => 'view/phui/PHUIDocumentSummaryView.php',
|
||||
'PHUIDocumentView' => 'view/phui/PHUIDocumentView.php',
|
||||
'PHUIDocumentViewPro' => 'view/phui/PHUIDocumentViewPro.php',
|
||||
'PHUIFeedStoryExample' => 'applications/uiexample/examples/PHUIFeedStoryExample.php',
|
||||
'PHUIFeedStoryView' => 'view/phui/PHUIFeedStoryView.php',
|
||||
|
@ -2268,7 +2266,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCustomFieldStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStorage.php',
|
||||
'PhabricatorCustomFieldStorageQuery' => 'infrastructure/customfield/query/PhabricatorCustomFieldStorageQuery.php',
|
||||
'PhabricatorCustomFieldStringIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStringIndexStorage.php',
|
||||
'PhabricatorCustomHeaderConfigType' => 'applications/config/custom/PhabricatorCustomHeaderConfigType.php',
|
||||
'PhabricatorCustomLogoConfigType' => 'applications/config/custom/PhabricatorCustomLogoConfigType.php',
|
||||
'PhabricatorDaemon' => 'infrastructure/daemon/PhabricatorDaemon.php',
|
||||
'PhabricatorDaemonBulkJobController' => 'applications/daemon/controller/PhabricatorDaemonBulkJobController.php',
|
||||
'PhabricatorDaemonBulkJobListController' => 'applications/daemon/controller/PhabricatorDaemonBulkJobListController.php',
|
||||
|
@ -3383,6 +3381,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorRepositoryCommitPHIDType' => 'applications/repository/phid/PhabricatorRepositoryCommitPHIDType.php',
|
||||
'PhabricatorRepositoryCommitParserWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitParserWorker.php',
|
||||
'PhabricatorRepositoryCommitRef' => 'applications/repository/engine/PhabricatorRepositoryCommitRef.php',
|
||||
'PhabricatorRepositoryCommitTestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryCommitTestCase.php',
|
||||
'PhabricatorRepositoryConfigOptions' => 'applications/repository/config/PhabricatorRepositoryConfigOptions.php',
|
||||
'PhabricatorRepositoryDAO' => 'applications/repository/storage/PhabricatorRepositoryDAO.php',
|
||||
'PhabricatorRepositoryDiscoveryEngine' => 'applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php',
|
||||
|
@ -6270,9 +6269,7 @@ phutil_register_library_map(array(
|
|||
'PHUIDiffTableOfContentsItemView' => 'AphrontView',
|
||||
'PHUIDiffTableOfContentsListView' => 'AphrontView',
|
||||
'PHUIDiffTwoUpInlineCommentRowScaffold' => 'PHUIDiffInlineCommentRowScaffold',
|
||||
'PHUIDocumentExample' => 'PhabricatorUIExample',
|
||||
'PHUIDocumentSummaryView' => 'AphrontTagView',
|
||||
'PHUIDocumentView' => 'AphrontTagView',
|
||||
'PHUIDocumentViewPro' => 'AphrontTagView',
|
||||
'PHUIFeedStoryExample' => 'PhabricatorUIExample',
|
||||
'PHUIFeedStoryView' => 'AphrontView',
|
||||
|
@ -7014,7 +7011,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCustomFieldStorage' => 'PhabricatorLiskDAO',
|
||||
'PhabricatorCustomFieldStorageQuery' => 'Phobject',
|
||||
'PhabricatorCustomFieldStringIndexStorage' => 'PhabricatorCustomFieldIndexStorage',
|
||||
'PhabricatorCustomHeaderConfigType' => 'PhabricatorConfigOptionType',
|
||||
'PhabricatorCustomLogoConfigType' => 'PhabricatorConfigOptionType',
|
||||
'PhabricatorDaemon' => 'PhutilDaemon',
|
||||
'PhabricatorDaemonBulkJobController' => 'PhabricatorDaemonController',
|
||||
'PhabricatorDaemonBulkJobListController' => 'PhabricatorDaemonBulkJobController',
|
||||
|
@ -8342,6 +8339,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorRepositoryCommitPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorRepositoryCommitParserWorker' => 'PhabricatorWorker',
|
||||
'PhabricatorRepositoryCommitRef' => 'Phobject',
|
||||
'PhabricatorRepositoryCommitTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorRepositoryConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorRepositoryDAO' => 'PhabricatorLiskDAO',
|
||||
'PhabricatorRepositoryDiscoveryEngine' => 'PhabricatorRepositoryEngine',
|
||||
|
|
|
@ -28,6 +28,10 @@ final class PhabricatorCalendarApplication extends PhabricatorApplication {
|
|||
return "\xE2\x8C\xA8";
|
||||
}
|
||||
|
||||
public function getApplicationGroup() {
|
||||
return self::GROUP_UTILITIES;
|
||||
}
|
||||
|
||||
public function isPrototype() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -2,58 +2,6 @@
|
|||
|
||||
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() {
|
||||
$icons = $this->getDirectoryList('tokens_1x');
|
||||
$scales = array(
|
||||
|
|
|
@ -328,6 +328,10 @@ final class PhabricatorExtraConfigSetupCheck extends PhabricatorSetupCheck {
|
|||
|
||||
'metamta.re-prefix' => $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;
|
||||
|
|
|
@ -43,7 +43,6 @@ final class PhabricatorConfigClusterRepositoriesController
|
|||
|
||||
$all_repositories = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($viewer)
|
||||
->withHosted(PhabricatorRepositoryQuery::HOSTED_PHABRICATOR)
|
||||
->withTypes(
|
||||
array(
|
||||
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;
|
||||
if ($errors) {
|
||||
|
@ -144,9 +145,9 @@ final class PhabricatorConfigEditController
|
|||
}
|
||||
|
||||
if ($option->getHidden() || $option->getLocked()) {
|
||||
$control = null;
|
||||
$controls = array();
|
||||
} else {
|
||||
$control = $this->renderControl(
|
||||
$controls = $this->renderControls(
|
||||
$option,
|
||||
$display_value,
|
||||
$e_value);
|
||||
|
@ -201,9 +202,9 @@ final class PhabricatorConfigEditController
|
|||
}
|
||||
}
|
||||
|
||||
$form
|
||||
->appendChild($control);
|
||||
|
||||
foreach ($controls as $control) {
|
||||
$form->appendControl($control);
|
||||
}
|
||||
|
||||
if (!$option->getLocked()) {
|
||||
$form->appendChild(
|
||||
|
@ -279,23 +280,23 @@ final class PhabricatorConfigEditController
|
|||
$e_value = null;
|
||||
$errors = array();
|
||||
|
||||
$value = $request->getStr('value');
|
||||
if (!strlen($value)) {
|
||||
$value = null;
|
||||
|
||||
$xaction->setNewValue(
|
||||
array(
|
||||
'deleted' => true,
|
||||
'value' => null,
|
||||
));
|
||||
|
||||
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 {
|
||||
$value = $request->getStr('value');
|
||||
if (!strlen($value)) {
|
||||
$value = null;
|
||||
|
||||
$xaction->setNewValue(
|
||||
array(
|
||||
'deleted' => true,
|
||||
'value' => null,
|
||||
));
|
||||
|
||||
return array($e_value, $errors, $value, $xaction);
|
||||
}
|
||||
|
||||
$type = $option->getType();
|
||||
$set_value = null;
|
||||
|
||||
|
@ -415,13 +416,13 @@ final class PhabricatorConfigEditController
|
|||
}
|
||||
}
|
||||
|
||||
private function renderControl(
|
||||
private function renderControls(
|
||||
PhabricatorConfigOption $option,
|
||||
$display_value,
|
||||
$e_value) {
|
||||
|
||||
if ($option->isCustomType()) {
|
||||
$control = $option->getCustomObject()->renderControl(
|
||||
$controls = $option->getCustomObject()->renderControls(
|
||||
$option,
|
||||
$display_value,
|
||||
$e_value);
|
||||
|
@ -487,9 +488,11 @@ final class PhabricatorConfigEditController
|
|||
->setError($e_value)
|
||||
->setValue($display_value)
|
||||
->setName('value');
|
||||
|
||||
$controls = array($control);
|
||||
}
|
||||
|
||||
return $control;
|
||||
return $controls;
|
||||
}
|
||||
|
||||
private function renderExamples(PhabricatorConfigOption $option) {
|
||||
|
|
|
@ -358,7 +358,7 @@ final class PhabricatorConfigWelcomeController
|
|||
$quick_header = new PHUIRemarkupView(
|
||||
$viewer, pht('=Quick Start Guide'));
|
||||
|
||||
return id(new PHUIDocumentView())
|
||||
$document = id(new PHUIDocumentViewPro())
|
||||
->setHeader($header)
|
||||
->setFluid(true)
|
||||
->appendChild($setup_header)
|
||||
|
@ -367,6 +367,11 @@ final class PhabricatorConfigWelcomeController
|
|||
->appendChild($explore)
|
||||
->appendChild($quick_header)
|
||||
->appendChild($quick);
|
||||
|
||||
return id(new PHUIBoxView())
|
||||
->setBorder(true)
|
||||
->appendChild($document)
|
||||
->addClass('mlb');
|
||||
}
|
||||
|
||||
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(
|
||||
PhabricatorConfigOption $option,
|
||||
$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() {
|
||||
$custom_header_example =
|
||||
PhabricatorCustomHeaderConfigType::getExampleConfig();
|
||||
$experimental_link = 'https://secure.phabricator.com/T4214';
|
||||
$options = array(
|
||||
'blindigo' => 'blindigo',
|
||||
'red' => 'red',
|
||||
|
@ -48,11 +45,24 @@ final class PhabricatorUIConfigOptions
|
|||
]
|
||||
EOJSON;
|
||||
|
||||
$logo_type = 'custom:PhabricatorCustomLogoConfigType';
|
||||
|
||||
return array(
|
||||
$this->newOption('ui.header-color', 'enum', 'blindigo')
|
||||
->setDescription(
|
||||
pht('Sets the default color scheme of Phabricator.'))
|
||||
->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())
|
||||
->setSummary(
|
||||
pht(
|
||||
|
@ -69,31 +79,6 @@ EOJSON;
|
|||
" omit this if you just want a piece of text, like a copyright ".
|
||||
" notice."))
|
||||
->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);
|
||||
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)
|
||||
->setDataType($type)
|
||||
|
@ -182,11 +187,17 @@ abstract class PhabricatorConfigSchemaSpec extends Phobject {
|
|||
->setName($name);
|
||||
}
|
||||
|
||||
public function getMaximumByteLengthForDataType($data_type) {
|
||||
$info = $this->getDetailsForDataType($data_type);
|
||||
return idx($info, 'bytes');
|
||||
}
|
||||
|
||||
private function getDetailsForDataType($data_type) {
|
||||
$column_type = null;
|
||||
$charset = null;
|
||||
$collation = null;
|
||||
$auto = false;
|
||||
$bytes = null;
|
||||
|
||||
// If the type ends with "?", make the column nullable.
|
||||
$nullable = false;
|
||||
|
@ -211,7 +222,6 @@ abstract class PhabricatorConfigSchemaSpec extends Phobject {
|
|||
'text255' => true,
|
||||
'text160' => true,
|
||||
'text128' => true,
|
||||
'text80' => true,
|
||||
'text64' => true,
|
||||
'text40' => true,
|
||||
'text32' => true,
|
||||
|
@ -237,6 +247,10 @@ abstract class PhabricatorConfigSchemaSpec extends Phobject {
|
|||
$type = $matches[1];
|
||||
$size = idx($matches, 2);
|
||||
|
||||
if ($size) {
|
||||
$bytes = $size;
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case 'text':
|
||||
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)
|
||||
->setSudoAsDaemon(true)
|
||||
->setCredentialPHID($repository->getCredentialPHID())
|
||||
->setURI($repository->getRemoteURI())
|
||||
->setURI($repository->getRemoteURIObject())
|
||||
->newFuture();
|
||||
|
||||
$future->setCWD($local_path);
|
||||
|
|
|
@ -18,6 +18,10 @@ final class PhabricatorFeedApplication extends PhabricatorApplication {
|
|||
return 'fa-newspaper-o';
|
||||
}
|
||||
|
||||
public function getApplicationGroup() {
|
||||
return self::GROUP_UTILITIES;
|
||||
}
|
||||
|
||||
public function canUninstall() {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
final class HeraldRuleViewController extends HeraldController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
$id = $request->getURIData('id');
|
||||
|
|
|
@ -249,9 +249,13 @@ final class HeraldTranscriptController extends HeraldController {
|
|||
foreach ($rule_xscripts as $rule_xscript) {
|
||||
$rule_id = $rule_xscript->getRuleID();
|
||||
|
||||
$rule_monogram = pht('H%d', $rule_id);
|
||||
$rule_uri = '/'.$rule_monogram;
|
||||
|
||||
$rule_item = id(new PHUIObjectItemView())
|
||||
->setObjectName(pht('H%d', $rule_id))
|
||||
->setHeader($rule_xscript->getRuleName());
|
||||
->setObjectName($rule_monogram)
|
||||
->setHeader($rule_xscript->getRuleName())
|
||||
->setHref($rule_uri);
|
||||
|
||||
if (!$rule_xscript->getResult()) {
|
||||
$rule_item->setDisabled(true);
|
||||
|
|
|
@ -288,39 +288,40 @@ final class HeraldRule extends HeraldDAO
|
|||
}
|
||||
|
||||
public function getPolicy($capability) {
|
||||
if ($capability == PhabricatorPolicyCapability::CAN_VIEW) {
|
||||
return PhabricatorPolicies::getMostOpenPolicy();
|
||||
}
|
||||
|
||||
if ($this->isGlobalRule()) {
|
||||
switch ($capability) {
|
||||
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||
return PhabricatorPolicies::POLICY_USER;
|
||||
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||
$app = 'PhabricatorHeraldApplication';
|
||||
$herald = PhabricatorApplication::getByClass($app);
|
||||
$global = HeraldManageGlobalRulesCapability::CAPABILITY;
|
||||
return $herald->getPolicy($global);
|
||||
}
|
||||
$app = 'PhabricatorHeraldApplication';
|
||||
$herald = PhabricatorApplication::getByClass($app);
|
||||
$global = HeraldManageGlobalRulesCapability::CAPABILITY;
|
||||
return $herald->getPolicy($global);
|
||||
} else if ($this->isObjectRule()) {
|
||||
return $this->getTriggerObject()->getPolicy($capability);
|
||||
} else {
|
||||
return PhabricatorPolicies::POLICY_NOONE;
|
||||
return $this->getAuthorPHID();
|
||||
}
|
||||
}
|
||||
|
||||
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||
if ($this->isPersonalRule()) {
|
||||
return ($viewer->getPHID() == $this->getAuthorPHID());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function describeAutomaticCapability($capability) {
|
||||
if ($this->isPersonalRule()) {
|
||||
return pht("A personal rule's owner can always view and edit it.");
|
||||
} else if ($this->isObjectRule()) {
|
||||
return pht('Object rules inherit the policies of their objects.');
|
||||
if ($capability == PhabricatorPolicyCapability::CAN_VIEW) {
|
||||
return null;
|
||||
}
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
public function getApplicationGroup() {
|
||||
return self::GROUP_UTILITIES;
|
||||
}
|
||||
|
||||
public function isPrototype() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,10 @@ final class PhabricatorPeopleApplication extends PhabricatorApplication {
|
|||
return pht('Sort of a social utility.');
|
||||
}
|
||||
|
||||
public function getApplicationGroup() {
|
||||
return self::GROUP_UTILITIES;
|
||||
}
|
||||
|
||||
public function canUninstall() {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,10 @@ final class PhabricatorPhurlApplication extends PhabricatorApplication {
|
|||
return true;
|
||||
}
|
||||
|
||||
public function getApplicationGroup() {
|
||||
return self::GROUP_UTILITIES;
|
||||
}
|
||||
|
||||
public function getRemarkupRules() {
|
||||
return array(
|
||||
new PhabricatorPhurlRemarkupRule(),
|
||||
|
|
|
@ -34,6 +34,10 @@ final class PhabricatorPonderApplication extends PhabricatorApplication {
|
|||
);
|
||||
}
|
||||
|
||||
public function getApplicationGroup() {
|
||||
return self::GROUP_UTILITIES;
|
||||
}
|
||||
|
||||
public function supportsEmailIntegration() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,10 @@ final class PhabricatorReleephApplication extends PhabricatorApplication {
|
|||
return 'fa-flag-checkered';
|
||||
}
|
||||
|
||||
public function getApplicationGroup() {
|
||||
return self::GROUP_UTILITIES;
|
||||
}
|
||||
|
||||
public function isPrototype() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ final class PhabricatorRepositoryCommit
|
|||
'mailKey' => 'bytes20',
|
||||
'authorPHID' => 'phid?',
|
||||
'auditStatus' => 'uint32',
|
||||
'summary' => 'text80',
|
||||
'summary' => 'text255',
|
||||
'importStatus' => 'uint32',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
|
|
|
@ -2,12 +2,6 @@
|
|||
|
||||
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 $authorName = '';
|
||||
protected $commitMessage = '';
|
||||
|
@ -38,10 +32,14 @@ final class PhabricatorRepositoryCommitData extends PhabricatorRepositoryDAO {
|
|||
}
|
||||
|
||||
public static function summarizeCommitMessage($message) {
|
||||
$max_bytes = id(new PhabricatorRepositoryCommit())
|
||||
->getColumnMaximumByteLength('summary');
|
||||
|
||||
$summary = phutil_split_lines($message, $retain_endings = false);
|
||||
$summary = head($summary);
|
||||
$summary = id(new PhutilUTF8StringTruncator())
|
||||
->setMaximumBytes(self::SUMMARY_MAX_LENGTH)
|
||||
->setMaximumBytes($max_bytes)
|
||||
->setMaximumGlyphs(80)
|
||||
->truncateString($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.
|
||||
|
||||
= Overview =
|
||||
Overview
|
||||
========
|
||||
|
||||
Herald allows you to write processing rules that take effect when objects (such
|
||||
as Differential revisions and commits) are created or updated. For instance, you
|
||||
might want to get notified every time someone sends out a revision that affects
|
||||
some file you're interested in, even if they didn't add you as a reviewer.
|
||||
Herald allows you to write rules which run automatically when objects (like
|
||||
tasks or commits) are created or updated. For instance, you might want to get
|
||||
notified every time someone sends out a revision that affects some file you're
|
||||
interested in, even if they didn't add you as a reviewer.
|
||||
|
||||
Herald is less useful for small organizations (where everyone will generally
|
||||
know most of what's going on) but the usefulness of the application increases
|
||||
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.
|
||||
One way to think about Herald is that it is a lot like 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
|
||||
and commits) instead of emails.
|
||||
|
||||
Every time an object is created or updated, Herald rules are run on it and
|
||||
the actions for any matching rules are taken.
|
||||
For example, you can write a personal rule like this which triggers on tasks:
|
||||
|
||||
To create a new Herald rule, choose which type of event you want to act on
|
||||
(e.g., changes to Differential Revisions, or Commits), and then set a list of
|
||||
conditions. For example, you might add the condition `Author is alincoln
|
||||
(Abraham Lincoln)` to keep track of everything alincoln does. Finally, set
|
||||
a list of actions to take when the conditions match, like adding yourself to the
|
||||
CC list.
|
||||
> When [ all of ] these conditions are met:
|
||||
> [ Title ][ contains ][ quasar ]
|
||||
> Take these actions [ every time ] this rule matches:
|
||||
> [ Add me as a subscriber ]
|
||||
|
||||
Now you'll automatically be added to CC any time alincoln creates a revision,
|
||||
and can keep an eye on what he's up to.
|
||||
This rule will automatically subscribe you to any newly created or updated
|
||||
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
|
||||
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.
|
||||
Working with Rules
|
||||
==================
|
||||
|
||||
= 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
|
||||
revision or commit and Herald will do 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.
|
||||
Next, you'll choose an event that you want to write a rule for: for example,
|
||||
a rule for when commits are discovered or a rule for when tasks are created or
|
||||
updated.
|
||||
|
||||
= 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
|
||||
like "Any changed file content matches regexp pair...". This 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.
|
||||
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.
|
||||
- **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 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
|
||||
conditions, you can set the action to "Do Nothing".
|
||||
To test rules, use {nav Herald > Test Console}. See "Testing Rules" below
|
||||
for greater detail.
|
||||
|
||||
To review which rules did or did not trigger for a particular event (and why),
|
||||
see {nav Herald > Transcripts}.
|
||||
|
||||
|
||||
Rule Types
|
||||
==========
|
||||
|
||||
You can create three kinds of Herald rules: personal rules, object rules, and
|
||||
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) {
|
||||
LiskDAO::closeAllConnections();
|
||||
LiskDAO::closeInactiveConnections(60);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,24 @@ abstract class PhabricatorDaemon extends PhutilDaemon {
|
|||
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
|
||||
// PATH.
|
||||
$sudo = Filesystem::resolveBinary('sudo');
|
||||
|
|
|
@ -1621,10 +1621,55 @@ abstract class LiskDAO extends Phobject {
|
|||
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 )---------------------------------------------------------- */
|
||||
|
||||
|
||||
|
@ -1831,7 +1876,6 @@ abstract class LiskDAO extends Phobject {
|
|||
return $this->getConfigOption(self::CONFIG_BINARY);
|
||||
}
|
||||
|
||||
|
||||
public function getSchemaColumns() {
|
||||
$custom_map = $this->getConfigOption(self::CONFIG_COLUMN_SCHEMA);
|
||||
if (!$custom_map) {
|
||||
|
@ -1953,4 +1997,21 @@ abstract class LiskDAO extends Phobject {
|
|||
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,15 +122,16 @@ abstract class PhabricatorLiskDAO extends LiskDAO {
|
|||
}
|
||||
|
||||
$replica = PhabricatorDatabaseRef::getReplicaDatabaseRef();
|
||||
if (!$replica) {
|
||||
throw new Exception(
|
||||
pht('No valid databases are configured!'));
|
||||
if ($replica) {
|
||||
$connection = $replica->newApplicationConnection($database);
|
||||
$connection->setReadOnly(true);
|
||||
if ($replica->isReachable($connection)) {
|
||||
return $connection;
|
||||
}
|
||||
}
|
||||
|
||||
$connection = $replica->newApplicationConnection($database);
|
||||
$connection->setReadOnly(true);
|
||||
if ($replica->isReachable($connection)) {
|
||||
return $connection;
|
||||
if (!$master && !$replica) {
|
||||
$this->raiseUnconfigured($database);
|
||||
}
|
||||
|
||||
$this->raiseUnreachable($database);
|
||||
|
@ -153,10 +154,18 @@ abstract class PhabricatorLiskDAO extends LiskDAO {
|
|||
$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) {
|
||||
throw new PhabricatorClusterStrandedException(
|
||||
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 '.
|
||||
'unreachable.',
|
||||
$database));
|
||||
|
|
|
@ -31,7 +31,7 @@ final class PhabricatorStorageManagementShellWorkflow
|
|||
}
|
||||
|
||||
return phutil_passthru(
|
||||
'mysql --protocol=TCP --default-character-set=utf8 '.
|
||||
'mysql --protocol=TCP --default-character-set=utf8mb4 '.
|
||||
'-u %s %C -h %s %C',
|
||||
$api->getUser(),
|
||||
$flag_password,
|
||||
|
|
|
@ -297,11 +297,13 @@ final class PhabricatorMainMenuView extends AphrontView {
|
|||
}
|
||||
|
||||
private function renderPhabricatorLogo() {
|
||||
$style_logo = null;
|
||||
$custom_header = PhabricatorEnv::getEnvConfig('ui.custom-header');
|
||||
$custom_header = PhabricatorCustomLogoConfigType::getLogoImagePHID();
|
||||
|
||||
$logo_style = array();
|
||||
if ($custom_header) {
|
||||
$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);
|
||||
if (!$logo_uri) {
|
||||
$file = id(new PhabricatorFileQuery())
|
||||
|
@ -313,21 +315,32 @@ final class PhabricatorMainMenuView extends AphrontView {
|
|||
$cache->setKey($cache_key_logo, $logo_uri);
|
||||
}
|
||||
}
|
||||
if ($logo_uri) {
|
||||
$style_logo =
|
||||
'background-size: 96px 40px; '.
|
||||
'background-position: 0px 0px; '.
|
||||
'background-image: url('.$logo_uri.');';
|
||||
}
|
||||
|
||||
$logo_style[] = 'background-size: 40px 40px;';
|
||||
$logo_style[] = 'background-position: 0 0;';
|
||||
$logo_style[] = 'background-image: url('.$logo_uri.')';
|
||||
}
|
||||
|
||||
$color = PhabricatorEnv::getEnvConfig('ui.header-color');
|
||||
if ($color == 'light') {
|
||||
$color = 'dark';
|
||||
} else {
|
||||
$color = 'light';
|
||||
$logo_node = phutil_tag(
|
||||
'span',
|
||||
array(
|
||||
'class' => 'phabricator-main-menu-eye',
|
||||
'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(
|
||||
'a',
|
||||
array(
|
||||
|
@ -341,19 +354,8 @@ final class PhabricatorMainMenuView extends AphrontView {
|
|||
'aural' => true,
|
||||
),
|
||||
pht('Home')),
|
||||
phutil_tag(
|
||||
'span',
|
||||
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,
|
||||
),
|
||||
''),
|
||||
$logo_node,
|
||||
$wordmark_node,
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
.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 {
|
||||
width: 205px;
|
||||
padding: 0;
|
||||
|
|
|
@ -41,27 +41,20 @@
|
|||
}
|
||||
|
||||
.phabricator-main-menu-brand {
|
||||
display: inline-block;
|
||||
width: 148px;
|
||||
height: 44px;
|
||||
float: left;
|
||||
margin-right: 4px;
|
||||
margin-right: 6px;
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
.phabricator-main-menu-logo {
|
||||
position: absolute;
|
||||
width: 96px;
|
||||
height: 40px;
|
||||
left: 52px;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.phabricator-main-menu-eye {
|
||||
position: absolute;
|
||||
margin: 2px 0;
|
||||
width: 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 {
|
||||
|
@ -69,6 +62,21 @@
|
|||
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 ----------------------------------------------------
|
||||
|
||||
On phones, the menu switches to a vertical layout and uses a button to expand
|
||||
|
|
|
@ -19,5 +19,10 @@
|
|||
width: 32px;
|
||||
float: left;
|
||||
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;
|
||||
}
|
||||
|
||||
.phui-document-view .phui-header-shell {
|
||||
padding: 16px;
|
||||
background-color: {$bluebackground};
|
||||
}
|
||||
|
||||
.phui-document-content {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.device-desktop .phui-document-view {
|
||||
border: 1px solid {$lightblueborder};
|
||||
max-width: 960px;
|
||||
|
@ -33,44 +24,11 @@
|
|||
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 */
|
||||
.device-desktop .phui-remarkup-preview .phui-document-view {
|
||||
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 {
|
||||
border-top: none;
|
||||
border-bottom: 1px solid {$lightblueborder};
|
||||
|
@ -88,11 +46,6 @@
|
|||
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 {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
|
@ -127,18 +80,10 @@
|
|||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.device-desktop .phui-document-offset {
|
||||
padding-right: 120px;
|
||||
}
|
||||
|
||||
.phui-document-view .phui-info-severity-nodata {
|
||||
background-color: {$lightgreybackground};
|
||||
}
|
||||
|
||||
body .phui-document-view .phui-header-shell.phui-bleed-header {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.phui-document-view .phui-property-list-section-header {
|
||||
padding: 20px 24px 0px;
|
||||
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 |