diff --git a/resources/celerity/map.php b/resources/celerity/map.php index cc948cc4f5..8875583e99 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -7,12 +7,12 @@ */ return array( 'names' => array( - 'core.pkg.css' => 'eb8c668d', + 'core.pkg.css' => 'a2cf2f6c', 'core.pkg.js' => '47dc9ebb', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '2de124c9', - 'differential.pkg.js' => '813c1633', - 'diffusion.pkg.css' => '385e85b3', + 'differential.pkg.js' => '6223dd9d', + 'diffusion.pkg.css' => 'f45955ed', 'diffusion.pkg.js' => '0115b37c', 'maniphest.pkg.css' => '4845691a', 'maniphest.pkg.js' => '3ec6a6d5', @@ -20,12 +20,12 @@ return array( 'rsrc/css/aphront/dark-console.css' => '6378ef3d', 'rsrc/css/aphront/dialog-view.css' => 'fe58b18d', 'rsrc/css/aphront/lightbox-attachment.css' => '7acac05d', - 'rsrc/css/aphront/list-filter-view.css' => 'aa5ffcb9', + 'rsrc/css/aphront/list-filter-view.css' => '5d6f0526', 'rsrc/css/aphront/multi-column.css' => 'fd18389d', 'rsrc/css/aphront/notification.css' => '9c279160', 'rsrc/css/aphront/panel-view.css' => '8427b78d', 'rsrc/css/aphront/phabricator-nav-view.css' => 'a24cb589', - 'rsrc/css/aphront/table-view.css' => 'e3632cc9', + 'rsrc/css/aphront/table-view.css' => '34ee903e', 'rsrc/css/aphront/tokenizer.css' => '04875312', 'rsrc/css/aphront/tooltip.css' => '7672b60f', 'rsrc/css/aphront/typeahead-browse.css' => 'd8581d2c', @@ -65,7 +65,7 @@ return array( 'rsrc/css/application/differential/revision-history.css' => '0e8eb855', 'rsrc/css/application/differential/revision-list.css' => 'f3c47d33', 'rsrc/css/application/differential/table-of-contents.css' => 'ae4b7a55', - 'rsrc/css/application/diffusion/diffusion-icons.css' => '4ba18923', + 'rsrc/css/application/diffusion/diffusion-icons.css' => '2941baf1', 'rsrc/css/application/diffusion/diffusion-readme.css' => '2106ea08', 'rsrc/css/application/diffusion/diffusion-source.css' => '66fdf661', 'rsrc/css/application/feed/feed.css' => 'ecd4ec57', @@ -104,7 +104,7 @@ return array( 'rsrc/css/application/tokens/tokens.css' => '3d0f239e', 'rsrc/css/application/uiexample/example.css' => '528b19de', 'rsrc/css/core/core.css' => 'a76cefc9', - 'rsrc/css/core/remarkup.css' => 'ef286a6e', + 'rsrc/css/core/remarkup.css' => '1c4ac273', 'rsrc/css/core/syntax.css' => '9fd11da8', 'rsrc/css/core/z-index.css' => '57ddcaa2', 'rsrc/css/diviner/diviner-shared.css' => '5a337049', @@ -138,7 +138,7 @@ return array( 'rsrc/css/phui/phui-info-view.css' => '5b16bac6', 'rsrc/css/phui/phui-list.css' => '125599df', 'rsrc/css/phui/phui-object-box.css' => '407eaf5a', - 'rsrc/css/phui/phui-object-item-list-view.css' => 'ab1bf393', + 'rsrc/css/phui/phui-object-item-list-view.css' => '26c30d3f', 'rsrc/css/phui/phui-pager.css' => 'bea33d23', 'rsrc/css/phui/phui-pinboard-view.css' => '2495140e', 'rsrc/css/phui/phui-property-list-view.css' => '03904f6b', @@ -276,14 +276,10 @@ return array( 'rsrc/image/icon/fatcow/flag_purple.png' => 'cc517522', 'rsrc/image/icon/fatcow/flag_red.png' => '04ec726f', 'rsrc/image/icon/fatcow/flag_yellow.png' => '73946fd4', - 'rsrc/image/icon/fatcow/folder.png' => '95a435af', - 'rsrc/image/icon/fatcow/folder_go.png' => '001cbc94', 'rsrc/image/icon/fatcow/key_question.png' => '52a0c26a', 'rsrc/image/icon/fatcow/link.png' => '7afd4d5e', 'rsrc/image/icon/fatcow/page_white_edit.png' => '39a2eed8', - 'rsrc/image/icon/fatcow/page_white_link.png' => 'a90023c7', 'rsrc/image/icon/fatcow/page_white_put.png' => '08c95a0c', - 'rsrc/image/icon/fatcow/page_white_text.png' => '1e1f79c3', 'rsrc/image/icon/fatcow/source/conduit.png' => '4ea01d2f', 'rsrc/image/icon/fatcow/source/email.png' => '9bab3239', 'rsrc/image/icon/fatcow/source/fax.png' => '04195e68', @@ -357,13 +353,13 @@ return array( 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375', 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', 'rsrc/js/application/differential/ChangesetViewManager.js' => '58562350', - 'rsrc/js/application/differential/DifferentialInlineCommentEditor.js' => 'd4c87bf4', + 'rsrc/js/application/differential/DifferentialInlineCommentEditor.js' => '64a5550f', 'rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js' => 'e10f8e18', 'rsrc/js/application/differential/behavior-comment-jump.js' => '4fdb476d', 'rsrc/js/application/differential/behavior-comment-preview.js' => 'b064af76', 'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1', 'rsrc/js/application/differential/behavior-dropdown-menus.js' => '2035b9cb', - 'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '037b59eb', + 'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '65ef6074', 'rsrc/js/application/differential/behavior-keyboard-nav.js' => '2c426492', 'rsrc/js/application/differential/behavior-populate.js' => '8694b1df', 'rsrc/js/application/differential/behavior-toggle-files.js' => 'ca3f91eb', @@ -429,7 +425,7 @@ return array( 'rsrc/js/application/uiexample/gesture-example.js' => '558829c2', 'rsrc/js/application/uiexample/notification-example.js' => '8ce821c5', 'rsrc/js/core/Busy.js' => '59a7976a', - 'rsrc/js/core/DragAndDropFileUpload.js' => '07de8873', + 'rsrc/js/core/DragAndDropFileUpload.js' => 'ad10aeac', 'rsrc/js/core/DraggableList.js' => 'a16ec1c6', 'rsrc/js/core/FileUpload.js' => '477359c8', 'rsrc/js/core/Hovercard.js' => '14ac66f5', @@ -493,10 +489,10 @@ return array( 'aphront-bars' => '231ac33c', 'aphront-dark-console-css' => '6378ef3d', 'aphront-dialog-view-css' => 'fe58b18d', - 'aphront-list-filter-view-css' => 'aa5ffcb9', + 'aphront-list-filter-view-css' => '5d6f0526', 'aphront-multi-column-view-css' => 'fd18389d', 'aphront-panel-view-css' => '8427b78d', - 'aphront-table-view-css' => 'e3632cc9', + 'aphront-table-view-css' => '34ee903e', 'aphront-tokenizer-control-css' => '04875312', 'aphront-tooltip-css' => '7672b60f', 'aphront-typeahead-control-css' => '0e403212', @@ -517,13 +513,13 @@ return array( 'conpherence-widget-pane-css' => '775eaaba', 'differential-changeset-view-css' => 'b6b0d1bb', 'differential-core-view-css' => '7ac3cabc', - 'differential-inline-comment-editor' => 'd4c87bf4', + 'differential-inline-comment-editor' => '64a5550f', 'differential-revision-add-comment-css' => 'c47f8c40', 'differential-revision-comment-css' => '14b8565a', 'differential-revision-history-css' => '0e8eb855', 'differential-revision-list-css' => 'f3c47d33', 'differential-table-of-contents-css' => 'ae4b7a55', - 'diffusion-icons-css' => '4ba18923', + 'diffusion-icons-css' => '2941baf1', 'diffusion-readme-css' => '2106ea08', 'diffusion-source-css' => '66fdf661', 'diviner-shared-css' => '5a337049', @@ -568,7 +564,7 @@ return array( 'javelin-behavior-differential-comment-jump' => '4fdb476d', 'javelin-behavior-differential-diff-radios' => 'e1ff79b1', 'javelin-behavior-differential-dropdown-menus' => '2035b9cb', - 'javelin-behavior-differential-edit-inline-comments' => '037b59eb', + 'javelin-behavior-differential-edit-inline-comments' => '65ef6074', 'javelin-behavior-differential-feedback-preview' => 'b064af76', 'javelin-behavior-differential-keyboard-navigation' => '2c426492', 'javelin-behavior-differential-populate' => '8694b1df', @@ -718,7 +714,7 @@ return array( 'phabricator-core-css' => 'a76cefc9', 'phabricator-countdown-css' => 'e7544472', 'phabricator-dashboard-css' => 'eb458607', - 'phabricator-drag-and-drop-file-upload' => '07de8873', + 'phabricator-drag-and-drop-file-upload' => 'ad10aeac', 'phabricator-draggable-list' => 'a16ec1c6', 'phabricator-fatal-config-template-css' => '8e6c6fcd', 'phabricator-feed-css' => 'ecd4ec57', @@ -737,7 +733,7 @@ return array( 'phabricator-object-selector-css' => '85ee8ce6', 'phabricator-phtize' => 'd254d646', 'phabricator-prefab' => '6920d200', - 'phabricator-remarkup-css' => 'ef286a6e', + 'phabricator-remarkup-css' => '1c4ac273', 'phabricator-search-results-css' => '7dea472c', 'phabricator-shaped-request' => '7cbe244b', 'phabricator-side-menu-view-css' => 'bec2458e', @@ -791,7 +787,7 @@ return array( 'phui-inline-comment-view-css' => '0fdb3667', 'phui-list-view-css' => '125599df', 'phui-object-box-css' => '407eaf5a', - 'phui-object-item-list-view-css' => 'ab1bf393', + 'phui-object-item-list-view-css' => '26c30d3f', 'phui-pager-css' => 'bea33d23', 'phui-pinboard-view-css' => '2495140e', 'phui-property-list-view-css' => '03904f6b', @@ -853,14 +849,6 @@ return array( 'javelin-behavior-device', 'phabricator-title', ), - '037b59eb' => array( - 'javelin-behavior', - 'javelin-stratcom', - 'javelin-dom', - 'javelin-util', - 'javelin-vector', - 'differential-inline-comment-editor', - ), '048330fa' => array( 'javelin-behavior', 'javelin-typeahead-ondemand-source', @@ -885,14 +873,6 @@ return array( 'javelin-stratcom', 'javelin-workflow', ), - '07de8873' => array( - 'javelin-install', - 'javelin-util', - 'javelin-request', - 'javelin-dom', - 'javelin-uri', - 'phabricator-file-upload', - ), '087e919c' => array( 'javelin-install', 'javelin-dom', @@ -1297,6 +1277,22 @@ return array( 'javelin-workflow', 'javelin-dom', ), + '64a5550f' => array( + 'javelin-dom', + 'javelin-util', + 'javelin-stratcom', + 'javelin-install', + 'javelin-request', + 'javelin-workflow', + ), + '65ef6074' => array( + 'javelin-behavior', + 'javelin-stratcom', + 'javelin-dom', + 'javelin-util', + 'javelin-vector', + 'differential-inline-comment-editor', + ), '665cf6ac' => array( 'javelin-behavior', 'javelin-util', @@ -1658,6 +1654,14 @@ return array( 'javelin-stratcom', 'javelin-install', ), + 'ad10aeac' => array( + 'javelin-install', + 'javelin-util', + 'javelin-request', + 'javelin-dom', + 'javelin-uri', + 'phabricator-file-upload', + ), 'b064af76' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1817,14 +1821,6 @@ return array( 'javelin-dom', 'javelin-view', ), - 'd4c87bf4' => array( - 'javelin-dom', - 'javelin-util', - 'javelin-stratcom', - 'javelin-install', - 'javelin-request', - 'javelin-workflow', - ), 'd4eecc63' => array( 'javelin-behavior', 'javelin-dom', diff --git a/resources/sql/autopatches/20150910.owners.custom.1.sql b/resources/sql/autopatches/20150910.owners.custom.1.sql new file mode 100644 index 0000000000..112802a0b8 --- /dev/null +++ b/resources/sql/autopatches/20150910.owners.custom.1.sql @@ -0,0 +1,25 @@ +CREATE TABLE {$NAMESPACE}_owners.owners_customfieldstorage ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectPHID VARBINARY(64) NOT NULL, + fieldIndex BINARY(12) NOT NULL, + fieldValue LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}, + UNIQUE KEY (objectPHID, fieldIndex) +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; + +CREATE TABLE {$NAMESPACE}_owners.owners_customfieldstringindex ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectPHID VARBINARY(64) NOT NULL, + indexKey BINARY(12) NOT NULL, + indexValue LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}, + KEY `key_join` (objectPHID, indexKey, indexValue(64)), + KEY `key_find` (indexKey, indexValue(64)) +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; + +CREATE TABLE {$NAMESPACE}_owners.owners_customfieldnumericindex ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + objectPHID VARBINARY(64) NOT NULL, + indexKey BINARY(12) NOT NULL, + indexValue BIGINT NOT NULL, + KEY `key_join` (objectPHID, indexKey, indexValue), + KEY `key_find` (indexKey, indexValue) +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index f01d82e40f..c9db433f4b 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1842,6 +1842,7 @@ phutil_register_library_map(array( 'PhabricatorConfigOptionType' => 'applications/config/custom/PhabricatorConfigOptionType.php', 'PhabricatorConfigPHIDModule' => 'applications/config/module/PhabricatorConfigPHIDModule.php', 'PhabricatorConfigProxySource' => 'infrastructure/env/PhabricatorConfigProxySource.php', + 'PhabricatorConfigPurgeCacheController' => 'applications/config/controller/PhabricatorConfigPurgeCacheController.php', 'PhabricatorConfigRequestExceptionHandlerModule' => 'applications/config/module/PhabricatorConfigRequestExceptionHandlerModule.php', 'PhabricatorConfigResponse' => 'applications/config/response/PhabricatorConfigResponse.php', 'PhabricatorConfigSchemaQuery' => 'applications/config/schema/PhabricatorConfigSchemaQuery.php', @@ -2437,7 +2438,12 @@ phutil_register_library_map(array( 'PhabricatorOwnerPathQuery' => 'applications/owners/query/PhabricatorOwnerPathQuery.php', 'PhabricatorOwnersApplication' => 'applications/owners/application/PhabricatorOwnersApplication.php', 'PhabricatorOwnersConfigOptions' => 'applications/owners/config/PhabricatorOwnersConfigOptions.php', + 'PhabricatorOwnersConfiguredCustomField' => 'applications/owners/customfield/PhabricatorOwnersConfiguredCustomField.php', 'PhabricatorOwnersController' => 'applications/owners/controller/PhabricatorOwnersController.php', + 'PhabricatorOwnersCustomField' => 'applications/owners/customfield/PhabricatorOwnersCustomField.php', + 'PhabricatorOwnersCustomFieldNumericIndex' => 'applications/owners/storage/PhabricatorOwnersCustomFieldNumericIndex.php', + 'PhabricatorOwnersCustomFieldStorage' => 'applications/owners/storage/PhabricatorOwnersCustomFieldStorage.php', + 'PhabricatorOwnersCustomFieldStringIndex' => 'applications/owners/storage/PhabricatorOwnersCustomFieldStringIndex.php', 'PhabricatorOwnersDAO' => 'applications/owners/storage/PhabricatorOwnersDAO.php', 'PhabricatorOwnersDetailController' => 'applications/owners/controller/PhabricatorOwnersDetailController.php', 'PhabricatorOwnersEditController' => 'applications/owners/controller/PhabricatorOwnersEditController.php', @@ -5743,6 +5749,7 @@ phutil_register_library_map(array( 'PhabricatorConfigOptionType' => 'Phobject', 'PhabricatorConfigPHIDModule' => 'PhabricatorConfigModule', 'PhabricatorConfigProxySource' => 'PhabricatorConfigSource', + 'PhabricatorConfigPurgeCacheController' => 'PhabricatorConfigController', 'PhabricatorConfigRequestExceptionHandlerModule' => 'PhabricatorConfigModule', 'PhabricatorConfigResponse' => 'AphrontStandaloneHTMLResponse', 'PhabricatorConfigSchemaQuery' => 'Phobject', @@ -6425,7 +6432,15 @@ phutil_register_library_map(array( 'PhabricatorOwnerPathQuery' => 'Phobject', 'PhabricatorOwnersApplication' => 'PhabricatorApplication', 'PhabricatorOwnersConfigOptions' => 'PhabricatorApplicationConfigOptions', + 'PhabricatorOwnersConfiguredCustomField' => array( + 'PhabricatorOwnersCustomField', + 'PhabricatorStandardCustomFieldInterface', + ), 'PhabricatorOwnersController' => 'PhabricatorController', + 'PhabricatorOwnersCustomField' => 'PhabricatorCustomField', + 'PhabricatorOwnersCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage', + 'PhabricatorOwnersCustomFieldStorage' => 'PhabricatorCustomFieldStorage', + 'PhabricatorOwnersCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage', 'PhabricatorOwnersDAO' => 'PhabricatorLiskDAO', 'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController', 'PhabricatorOwnersEditController' => 'PhabricatorOwnersController', @@ -6435,6 +6450,7 @@ phutil_register_library_map(array( 'PhabricatorOwnersDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', + 'PhabricatorCustomFieldInterface', ), 'PhabricatorOwnersPackageDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorOwnersPackageFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', diff --git a/src/aphront/AphrontController.php b/src/aphront/AphrontController.php index ded0b362a3..4e5df8afbd 100644 --- a/src/aphront/AphrontController.php +++ b/src/aphront/AphrontController.php @@ -37,6 +37,10 @@ abstract class AphrontController extends Phobject { 'processRequest()')); } + public function willSendResponse(AphrontResponse $response) { + return $response; + } + final public function setRequest(AphrontRequest $request) { $this->request = $request; return $this; diff --git a/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php b/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php index 2523a1e333..160fe4f5db 100644 --- a/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php +++ b/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php @@ -6,7 +6,8 @@ final class PhabricatorCacheManagementPurgeWorkflow protected function didConstruct() { $this ->setName('purge') - ->setSynopsis(pht('Drop data from caches.')) + ->setSynopsis(pht('Drop data from caches. APC-based caches can be '. + 'purged from the web interface.')) ->setArguments( array( array( diff --git a/src/applications/cache/spec/PhabricatorCacheSpec.php b/src/applications/cache/spec/PhabricatorCacheSpec.php index 1688cb07fd..1ed4e713f1 100644 --- a/src/applications/cache/spec/PhabricatorCacheSpec.php +++ b/src/applications/cache/spec/PhabricatorCacheSpec.php @@ -5,6 +5,7 @@ abstract class PhabricatorCacheSpec extends Phobject { private $name; private $isEnabled = false; private $version; + private $clearCacheCallback = null; private $issues = array(); private $usedMemory = 0; @@ -108,4 +109,12 @@ abstract class PhabricatorCacheSpec extends Phobject { ->addPHPConfig('apc.enabled'); } + public function setClearCacheCallback($callback) { + $this->clearCacheCallback = $callback; + return $this; + } + + public function getClearCacheCallback() { + return $this->clearCacheCallback; + } } diff --git a/src/applications/cache/spec/PhabricatorDataCacheSpec.php b/src/applications/cache/spec/PhabricatorDataCacheSpec.php index b1364ff569..f5fe1c6277 100644 --- a/src/applications/cache/spec/PhabricatorDataCacheSpec.php +++ b/src/applications/cache/spec/PhabricatorDataCacheSpec.php @@ -34,7 +34,9 @@ final class PhabricatorDataCacheSpec extends PhabricatorCacheSpec { ->setVersion(phpversion('apc')); if (ini_get('apc.enabled')) { - $this->setIsEnabled(true); + $this + ->setIsEnabled(true) + ->setClearCacheCallback('apc_clear_cache'); $this->initAPCCommonSpec(); } else { $this->setIsEnabled(false); @@ -48,7 +50,9 @@ final class PhabricatorDataCacheSpec extends PhabricatorCacheSpec { ->setVersion(phpversion('apcu')); if (ini_get('apc.enabled')) { - $this->setIsEnabled(true); + $this + ->setIsEnabled(true) + ->setClearCacheCallback('apc_clear_cache'); $this->initAPCCommonSpec(); } else { $this->setIsEnabled(false); @@ -118,5 +122,4 @@ final class PhabricatorDataCacheSpec extends PhabricatorCacheSpec { return $key; } - } diff --git a/src/applications/cache/spec/PhabricatorOpcodeCacheSpec.php b/src/applications/cache/spec/PhabricatorOpcodeCacheSpec.php index c129fb0fa0..f9739a0328 100644 --- a/src/applications/cache/spec/PhabricatorOpcodeCacheSpec.php +++ b/src/applications/cache/spec/PhabricatorOpcodeCacheSpec.php @@ -23,7 +23,9 @@ final class PhabricatorOpcodeCacheSpec extends PhabricatorCacheSpec { ->setVersion(phpversion('apc')); if (ini_get('apc.enabled')) { - $this->setIsEnabled(true); + $this + ->setIsEnabled(true) + ->setClearCacheCallback('apc_clear_cache'); $mem = apc_sma_info(); $this->setTotalMemory($mem['num_seg'] * $mem['seg_size']); @@ -109,7 +111,9 @@ final class PhabricatorOpcodeCacheSpec extends PhabricatorCacheSpec { ->setVersion(phpversion('Zend OPcache')); if (ini_get('opcache.enable')) { - $this->setIsEnabled(true); + $this + ->setIsEnabled(true) + ->setClearCacheCallback('opcache_reset'); $status = opcache_get_status(); $memory = $status['memory_usage']; @@ -199,5 +203,4 @@ final class PhabricatorOpcodeCacheSpec extends PhabricatorCacheSpec { $this->raiseInstallAPCIssue(); } } - } diff --git a/src/applications/config/application/PhabricatorConfigApplication.php b/src/applications/config/application/PhabricatorConfigApplication.php index 8375881c24..36bac1d25b 100644 --- a/src/applications/config/application/PhabricatorConfigApplication.php +++ b/src/applications/config/application/PhabricatorConfigApplication.php @@ -55,7 +55,10 @@ final class PhabricatorConfigApplication extends PhabricatorApplication { '' => 'PhabricatorConfigIssueListController', '(?P[^/]+)/' => 'PhabricatorConfigIssueViewController', ), - 'cache/' => 'PhabricatorConfigCacheController', + 'cache/' => array( + '' => 'PhabricatorConfigCacheController', + 'purge/' => 'PhabricatorConfigPurgeCacheController', + ), 'module/' => array( '(?P[^/]+)/' => 'PhabricatorConfigModuleController', ), diff --git a/src/applications/config/controller/PhabricatorConfigCacheController.php b/src/applications/config/controller/PhabricatorConfigCacheController.php index a27be465e2..90c1b3a2fd 100644 --- a/src/applications/config/controller/PhabricatorConfigCacheController.php +++ b/src/applications/config/controller/PhabricatorConfigCacheController.php @@ -39,8 +39,22 @@ final class PhabricatorConfigCacheController $this->renderCommonProperties($properties, $cache); + $purge_icon = id(new PHUIIconView()) + ->setIconFont('fa-exclamation-triangle'); + + $purge_button = id(new PHUIButtonView()) + ->setText(pht('Purge Caches')) + ->setHref('/config/cache/purge/') + ->setTag('a') + ->setWorkflow(true) + ->setIcon($purge_icon); + + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Opcode Cache')) + ->addActionLink($purge_button); + return id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Opcode Cache')) + ->setHeader($header) ->addPropertyList($properties); } diff --git a/src/applications/config/controller/PhabricatorConfigPurgeCacheController.php b/src/applications/config/controller/PhabricatorConfigPurgeCacheController.php new file mode 100644 index 0000000000..9f40453fde --- /dev/null +++ b/src/applications/config/controller/PhabricatorConfigPurgeCacheController.php @@ -0,0 +1,62 @@ +getViewer(); + $cancel_uri = $this->getApplicationURI('cache/'); + + $opcode_cache = PhabricatorOpcodeCacheSpec::getActiveCacheSpec(); + $data_cache = PhabricatorDataCacheSpec::getActiveCacheSpec(); + + $opcode_clearable = $opcode_cache->getClearCacheCallback(); + $data_clearable = $data_cache->getClearCacheCallback(); + + if (!$opcode_clearable && !$data_clearable) { + return $this->newDialog() + ->setTitle(pht('No Caches to Reset')) + ->appendParagraph( + pht('None of the caches on this page can be cleared.')) + ->addCancelButton($cancel_uri); + } + + if ($request->isDialogFormPost()) { + if ($opcode_clearable) { + call_user_func($opcode_cache->getClearCacheCallback()); + } + + if ($data_clearable) { + call_user_func($data_cache->getClearCacheCallback()); + } + + return id(new AphrontRedirectResponse())->setURI($cancel_uri); + } + + $caches = id(new PHUIPropertyListView()) + ->setUser($viewer); + + if ($opcode_clearable) { + $caches->addProperty( + pht('Opcode'), + $opcode_cache->getName()); + } + + if ($data_clearable) { + $caches->addProperty( + pht('Data'), + $data_cache->getName()); + } + + return $this->newDialog() + ->setTitle(pht('Really Clear Cache?')) + ->setShortTitle(pht('Really Clear Cache')) + ->appendParagraph(pht('This will only affect the current web '. + 'frontend. Daemons and any other web frontends may continue '. + 'to use older, cached code from their opcache.')) + ->appendParagraph(pht('The following caches will be cleared:')) + ->appendChild($caches) + ->addSubmitButton(pht('Clear Cache')) + ->addCancelButton($cancel_uri); + } +} diff --git a/src/applications/config/management/PhabricatorConfigManagementSetWorkflow.php b/src/applications/config/management/PhabricatorConfigManagementSetWorkflow.php index 1da30408ee..97586a77dd 100644 --- a/src/applications/config/management/PhabricatorConfigManagementSetWorkflow.php +++ b/src/applications/config/management/PhabricatorConfigManagementSetWorkflow.php @@ -96,25 +96,35 @@ final class PhabricatorConfigManagementSetWorkflow if (!is_array($value)) { switch ($type) { case 'set': + $command = csprintf( + './bin/config set %R %s', + $key, + '{"value1": true, "value2": true}'); + $message = sprintf( - "%s%s\n\n %s\n", - pht( - "Config key '%s' is of type '%s'. Specify it in JSON.", - $key, - $type), - pht('For example:'), - './bin/config set \'{"value1": true, "value2": true}\''); + "%s\n\n %s\n", + pht( + 'Config key "%s" is of type "%s". Specify it in JSON. '. + 'For example:', + $key, + $type), + $command); break; default: if (preg_match('/^listsetMailReceiver(ConpherenceThread::initializeNewRoom($sender)) ->setMailAddedParticipantPHIDs($phids) ->setActor($sender) - ->setExcludeMailRecipientPHIDs($mail->loadExcludeMailRecipientPHIDs()) + ->setExcludeMailRecipientPHIDs($mail->loadAllRecipientPHIDs()) ->processEmail($mail); if ($conpherence) { diff --git a/src/applications/differential/constants/DifferentialChangeType.php b/src/applications/differential/constants/DifferentialChangeType.php index fb0fd58883..2bf4b217a7 100644 --- a/src/applications/differential/constants/DifferentialChangeType.php +++ b/src/applications/differential/constants/DifferentialChangeType.php @@ -66,6 +66,21 @@ final class DifferentialChangeType extends Phobject { return idx($names, coalesce($type, '?'), '???'); } + public static function getIconForFileType($type) { + static $icons = array( + self::FILE_TEXT => 'fa-file-text-o', + self::FILE_IMAGE => 'fa-file-image-o', + self::FILE_BINARY => 'fa-file', + self::FILE_DIRECTORY => 'fa-folder-open', + self::FILE_SYMLINK => 'fa-link', + self::FILE_DELETED => 'fa-file', + self::FILE_NORMAL => 'fa-file-text-o', + self::FILE_SUBMODULE => 'fa-folder-open-o', + ); + + return idx($icons, $type, 'fa-file'); + } + public static function isOldLocationChangeType($type) { static $types = array( self::TYPE_MOVE_AWAY => true, diff --git a/src/applications/diffusion/controller/DiffusionCommitController.php b/src/applications/diffusion/controller/DiffusionCommitController.php index 6117bcdaca..8a7d7d7d7c 100644 --- a/src/applications/diffusion/controller/DiffusionCommitController.php +++ b/src/applications/diffusion/controller/DiffusionCommitController.php @@ -856,6 +856,7 @@ final class DiffusionCommitController extends DiffusionController { } private function buildMergesTable(PhabricatorRepositoryCommit $commit) { + $viewer = $this->getViewer(); $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); @@ -892,15 +893,12 @@ final class DiffusionCommitController extends DiffusionController { new PhutilNumber($limit))); } - $history_table = new DiffusionHistoryTableView(); - $history_table->setUser($this->getRequest()->getUser()); - $history_table->setDiffusionRequest($drequest); - $history_table->setHistory($merges); - $history_table->loadRevisions(); + $history_table = id(new DiffusionHistoryTableView()) + ->setUser($viewer) + ->setDiffusionRequest($drequest) + ->setHistory($merges); - $phids = $history_table->getRequiredHandlePHIDs(); - $handles = $this->loadViewerHandles($phids); - $history_table->setHandles($handles); + $history_table->loadRevisions(); $panel = new PHUIObjectBoxView(); $panel->setHeaderText(pht('Merged Changes')); @@ -1110,7 +1108,11 @@ final class DiffusionCommitController extends DiffusionController { $anchor = substr(md5($path), 0, 8); $history_link = $diffusion_view->linkHistory($path); - $browse_link = $diffusion_view->linkBrowse($path); + $browse_link = $diffusion_view->linkBrowse( + $path, + array( + 'type' => $changeset->getFileType(), + )); $item = id(new PHUIDiffTableOfContentsItemView()) ->setChangeset($changeset) diff --git a/src/applications/diffusion/controller/DiffusionHistoryController.php b/src/applications/diffusion/controller/DiffusionHistoryController.php index 9dbcfc86dc..65286e9d34 100644 --- a/src/applications/diffusion/controller/DiffusionHistoryController.php +++ b/src/applications/diffusion/controller/DiffusionHistoryController.php @@ -42,15 +42,12 @@ final class DiffusionHistoryController extends DiffusionController { $show_graph = !strlen($drequest->getPath()); $content = array(); - $history_table = new DiffusionHistoryTableView(); - $history_table->setUser($request->getUser()); - $history_table->setDiffusionRequest($drequest); - $history_table->setHistory($history); - $history_table->loadRevisions(); + $history_table = id(new DiffusionHistoryTableView()) + ->setUser($request->getUser()) + ->setDiffusionRequest($drequest) + ->setHistory($history); - $phids = $history_table->getRequiredHandlePHIDs(); - $handles = $this->loadViewerHandles($phids); - $history_table->setHandles($handles); + $history_table->loadRevisions(); if ($show_graph) { $history_table->setParents($history_results['parents']); @@ -82,6 +79,10 @@ final class DiffusionHistoryController extends DiffusionController { 'view' => 'history', )); + $pager = id(new PHUIBoxView()) + ->addClass('ml') + ->appendChild($pager); + return $this->buildApplicationPage( array( $crumbs, diff --git a/src/applications/diffusion/controller/DiffusionRepositoryController.php b/src/applications/diffusion/controller/DiffusionRepositoryController.php index 7f2201e7fd..5b63f16d71 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryController.php @@ -177,8 +177,7 @@ final class DiffusionRepositoryController extends DiffusionController { $content[] = $this->buildHistoryTable( $history_results, $history, - $history_exception, - $handles); + $history_exception); try { $content[] = $this->buildTagListTable($drequest); @@ -519,8 +518,7 @@ final class DiffusionRepositoryController extends DiffusionController { private function buildHistoryTable( $history_results, $history, - $history_exception, - array $handles) { + $history_exception) { $request = $this->getRequest(); $viewer = $request->getUser(); @@ -544,7 +542,6 @@ final class DiffusionRepositoryController extends DiffusionController { $history_table = id(new DiffusionHistoryTableView()) ->setUser($viewer) ->setDiffusionRequest($drequest) - ->setHandles($handles) ->setHistory($history); // TODO: Super sketchy. diff --git a/src/applications/diffusion/view/DiffusionBrowseTableView.php b/src/applications/diffusion/view/DiffusionBrowseTableView.php index 35ba945f57..a8eb745fe4 100644 --- a/src/applications/diffusion/view/DiffusionBrowseTableView.php +++ b/src/applications/diffusion/view/DiffusionBrowseTableView.php @@ -40,25 +40,26 @@ final class DiffusionBrowseTableView extends DiffusionView { $browse_link = phutil_tag('strong', array(), $this->linkBrowse( $base_path.$path->getPath().$dir_slash, array( - 'text' => $this->renderPathIcon('dir', $browse_text), + 'type' => $file_type, + 'name' => $browse_text, ))); } else if ($file_type == DifferentialChangeType::FILE_SUBMODULE) { $browse_text = $path->getPath().'/'; - $browse_link = phutil_tag('strong', array(), $this->linkExternal( - $path->getHash(), - $path->getExternalURI(), - $this->renderPathIcon('ext', $browse_text))); + $browse_link = phutil_tag('strong', array(), $this->linkBrowse( + null, + array( + 'type' => $file_type, + 'name' => $browse_text, + 'hash' => $path->getHash(), + 'external' => $path->getExternalURI(), + ))); } else { - if ($file_type == DifferentialChangeType::FILE_SYMLINK) { - $type = 'link'; - } else { - $type = 'file'; - } $browse_text = $path->getPath(); $browse_link = $this->linkBrowse( $base_path.$path->getPath(), array( - 'text' => $this->renderPathIcon($type, $browse_text), + 'type' => $file_type, + 'name' => $browse_text, )); } @@ -151,16 +152,4 @@ final class DiffusionBrowseTableView extends DiffusionView { return $view->render(); } - private function renderPathIcon($type, $text) { - - require_celerity_resource('diffusion-icons-css'); - - return phutil_tag( - 'span', - array( - 'class' => 'diffusion-path-icon diffusion-path-icon-'.$type, - ), - $text); - } - } diff --git a/src/applications/diffusion/view/DiffusionEmptyResultView.php b/src/applications/diffusion/view/DiffusionEmptyResultView.php index 74a131e9d7..12def83e76 100644 --- a/src/applications/diffusion/view/DiffusionEmptyResultView.php +++ b/src/applications/diffusion/view/DiffusionEmptyResultView.php @@ -17,11 +17,11 @@ final class DiffusionEmptyResultView extends DiffusionView { public function render() { $drequest = $this->getDiffusionRequest(); + $repository = $drequest->getRepository(); $commit = $drequest->getCommit(); - $callsign = $drequest->getRepository()->getCallsign(); if ($commit) { - $commit = "r{$callsign}{$commit}"; + $commit = $repository->formatCommitName($commit); } else { $commit = 'HEAD'; } @@ -37,29 +37,38 @@ final class DiffusionEmptyResultView extends DiffusionView { break; case DiffusionBrowseResultSet::REASON_IS_EMPTY: $title = pht('Empty Directory'); - $body = pht("This path was an empty directory at %s.\n", $commit); + $body = pht('This path was an empty directory at %s.', $commit); $severity = PHUIInfoView::SEVERITY_NOTICE; break; case DiffusionBrowseResultSet::REASON_IS_DELETED: $deleted = $this->browseResultSet->getDeletedAtCommit(); $existed = $this->browseResultSet->getExistedAtCommit(); - $browse = $this->linkBrowse( - $drequest->getPath(), + $existed_text = $repository->formatCommitName($existed); + $existed_href = $drequest->generateURI( array( - 'text' => 'existed', + 'action' => 'browse', + 'path' => $drequest->getPath(), 'commit' => $existed, - 'params' => array('view' => $this->view), + 'params' => array( + 'view' => $this->view, + ), )); + $existed_link = phutil_tag( + 'a', + array( + 'href' => $existed_href, + ), + $existed_text); + $title = pht('Path Was Deleted'); $body = pht( - 'This path does not exist at %s. It was deleted in %s and last %s '. - 'at %s.', + 'This path does not exist at %s. It was deleted in %s and last '. + 'existed at %s.', $commit, self::linkCommit($drequest->getRepository(), $deleted), - $browse, - "r{$callsign}{$existed}"); + $existed_link); $severity = PHUIInfoView::SEVERITY_WARNING; break; case DiffusionBrowseResultSet::REASON_IS_UNTRACKED_PARENT: diff --git a/src/applications/diffusion/view/DiffusionHistoryTableView.php b/src/applications/diffusion/view/DiffusionHistoryTableView.php index ce1a693696..fd5f463b34 100644 --- a/src/applications/diffusion/view/DiffusionHistoryTableView.php +++ b/src/applications/diffusion/view/DiffusionHistoryTableView.php @@ -36,7 +36,7 @@ final class DiffusionHistoryTableView extends DiffusionView { return $this; } - public function getRequiredHandlePHIDs() { + private function getRequiredHandlePHIDs() { $phids = array(); foreach ($this->history as $item) { $data = $item->getCommitData(); @@ -87,7 +87,8 @@ final class DiffusionHistoryTableView extends DiffusionView { public function render() { $drequest = $this->getDiffusionRequest(); - $handles = $this->handles; + $viewer = $this->getUser(); + $handles = $viewer->loadHandles($this->getRequiredHandlePHIDs()); $graph = null; if ($this->parents) { @@ -188,8 +189,17 @@ final class DiffusionHistoryTableView extends DiffusionView { } } + $browse = $this->linkBrowse( + $history->getPath(), + array( + 'commit' => $history->getCommitIdentifier(), + 'branch' => $drequest->getBranch(), + 'type' => $history->getFileType(), + )); + $rows[] = array( $graph ? $graph[$ii++] : null, + $browse, self::linkCommit( $drequest->getRepository(), $history->getCommitIdentifier()), @@ -207,9 +217,10 @@ final class DiffusionHistoryTableView extends DiffusionView { $view = new AphrontTableView($rows); $view->setHeaders( array( - '', + null, + null, pht('Commit'), - '', + null, pht('Revision'), pht('Author/Committer'), pht('Details'), @@ -219,6 +230,7 @@ final class DiffusionHistoryTableView extends DiffusionView { $view->setColumnClasses( array( 'threads', + 'nudgeright', 'n', 'icon', 'n', @@ -237,6 +249,7 @@ final class DiffusionHistoryTableView extends DiffusionView { true, true, true, + true, false, true, false, diff --git a/src/applications/diffusion/view/DiffusionView.php b/src/applications/diffusion/view/DiffusionView.php index 0bc51f8347..b7b3599a2d 100644 --- a/src/applications/diffusion/view/DiffusionView.php +++ b/src/applications/diffusion/view/DiffusionView.php @@ -13,36 +13,6 @@ abstract class DiffusionView extends AphrontView { return $this->diffusionRequest; } - final public function linkChange( - $change_type, - $file_type, - $path = null, - $commit_identifier = null) { - - $text = DifferentialChangeType::getFullNameForChangeType($change_type); - if ($change_type == DifferentialChangeType::TYPE_CHILD) { - // TODO: Don't link COPY_AWAY without a direct change. - return $text; - } - if ($file_type == DifferentialChangeType::FILE_DIRECTORY) { - return $text; - } - - $href = $this->getDiffusionRequest()->generateURI( - array( - 'action' => 'change', - 'path' => $path, - 'commit' => $commit_identifier, - )); - - return phutil_tag( - 'a', - array( - 'href' => $href, - ), - $text); - } - final public function linkHistory($path) { $href = $this->getDiffusionRequest()->generateURI( array( @@ -50,50 +20,83 @@ abstract class DiffusionView extends AphrontView { 'path' => $path, )); - return phutil_tag( + return javelin_tag( 'a', array( 'href' => $href, + 'class' => 'diffusion-link-icon', + 'sigil' => 'has-tooltip', + 'meta' => array( + 'tip' => pht('History'), + 'align' => 'E', + ), ), - pht('History')); + id(new PHUIIconView())->setIconFont('fa-list-ul blue')); } final public function linkBrowse($path, array $details = array()) { + require_celerity_resource('diffusion-icons-css'); + Javelin::initBehavior('phabricator-tooltips'); - $href = $this->getDiffusionRequest()->generateURI( - $details + array( - 'action' => 'browse', - 'path' => $path, - )); + $file_type = idx($details, 'type'); + unset($details['type']); - if (isset($details['text'])) { - $text = $details['text']; - } else { - $text = pht('Browse'); + $display_name = idx($details, 'name'); + unset($details['name']); + + if (strlen($display_name)) { + $display_name = phutil_tag( + 'span', + array( + 'class' => 'diffusion-browse-name', + ), + $display_name); } - return phutil_tag( - 'a', - array( - 'href' => $href, - ), - $text); - } - - final public function linkExternal($hash, $uri, $text) { - $href = id(new PhutilURI('/diffusion/external/')) - ->setQueryParams( - array( - 'uri' => $uri, - 'id' => $hash, + if (isset($details['external'])) { + $href = id(new PhutilURI('/diffusion/external/')) + ->setQueryParams( + array( + 'uri' => idx($details, 'external'), + 'id' => idx($details, 'hash'), + )); + $tip = pht('Browse External'); + } else { + $href = $this->getDiffusionRequest()->generateURI( + $details + array( + 'action' => 'browse', + 'path' => $path, )); + $tip = pht('Browse'); + } - return phutil_tag( + $icon = DifferentialChangeType::getIconForFileType($file_type); + $icon_view = id(new PHUIIconView())->setIconFont("{$icon} blue"); + + // If we're rendering a file or directory name, don't show the tooltip. + if ($display_name !== null) { + $sigil = null; + $meta = null; + } else { + $sigil = 'has-tooltip'; + $meta = array( + 'tip' => $tip, + 'align' => 'E', + ); + } + + return javelin_tag( 'a', array( 'href' => $href, + 'class' => 'diffusion-link-icon', + 'sigil' => $sigil, + 'meta' => $meta, ), - $text); + array( + $icon_view, + $display_name, + )); } final public static function nameCommit( diff --git a/src/applications/harbormaster/autoplan/HarbormasterBuildArcanistAutoplan.php b/src/applications/harbormaster/autoplan/HarbormasterBuildArcanistAutoplan.php index 7b4d5f8433..f5b68334ed 100644 --- a/src/applications/harbormaster/autoplan/HarbormasterBuildArcanistAutoplan.php +++ b/src/applications/harbormaster/autoplan/HarbormasterBuildArcanistAutoplan.php @@ -10,7 +10,7 @@ final class HarbormasterBuildArcanistAutoplan } public function getAutoplanName() { - return pht('Arcanist Client Results'); + return pht('arc lint + arc unit'); } } diff --git a/src/applications/maniphest/mail/ManiphestCreateMailReceiver.php b/src/applications/maniphest/mail/ManiphestCreateMailReceiver.php index 0102b1bd7b..767a11d267 100644 --- a/src/applications/maniphest/mail/ManiphestCreateMailReceiver.php +++ b/src/applications/maniphest/mail/ManiphestCreateMailReceiver.php @@ -24,7 +24,7 @@ final class ManiphestCreateMailReceiver extends PhabricatorMailReceiver { $handler->setActor($sender); $handler->setExcludeMailRecipientPHIDs( - $mail->loadExcludeMailRecipientPHIDs()); + $mail->loadAllRecipientPHIDs()); if ($this->getApplicationEmail()) { $handler->setApplicationEmail($this->getApplicationEmail()); } diff --git a/src/applications/maniphest/mail/ManiphestReplyHandler.php b/src/applications/maniphest/mail/ManiphestReplyHandler.php index af96de70da..bc9b2456d4 100644 --- a/src/applications/maniphest/mail/ManiphestReplyHandler.php +++ b/src/applications/maniphest/mail/ManiphestReplyHandler.php @@ -19,17 +19,28 @@ final class ManiphestReplyHandler $object = $this->getMailReceiver(); $is_new = !$object->getID(); + $actor = $this->getActor(); $xactions = array(); if ($is_new) { - $xactions[] = $object->getApplicationTransactionTemplate() + $xactions[] = $this->newTransaction() ->setTransactionType(ManiphestTransaction::TYPE_TITLE) ->setNewValue(nonempty($mail->getSubject(), pht('Untitled Task'))); - $xactions[] = $object->getApplicationTransactionTemplate() + $xactions[] = $this->newTransaction() ->setTransactionType(ManiphestTransaction::TYPE_DESCRIPTION) ->setNewValue($body); + + $actor_phid = $actor->getPHID(); + if ($actor_phid) { + $xactions[] = $this->newTransaction() + ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS) + ->setNewValue( + array( + '+' => array($actor_phid), + )); + } } return $xactions; diff --git a/src/applications/metamta/receiver/PhabricatorObjectMailReceiver.php b/src/applications/metamta/receiver/PhabricatorObjectMailReceiver.php index 062eb52502..81f8ade37b 100644 --- a/src/applications/metamta/receiver/PhabricatorObjectMailReceiver.php +++ b/src/applications/metamta/receiver/PhabricatorObjectMailReceiver.php @@ -49,7 +49,7 @@ abstract class PhabricatorObjectMailReceiver extends PhabricatorMailReceiver { return $handler ->setMailReceiver($object) ->setActor($sender) - ->setExcludeMailRecipientPHIDs($mail->loadExcludeMailRecipientPHIDs()) + ->setExcludeMailRecipientPHIDs($mail->loadAllRecipientPHIDs()) ->processEmail($mail); } diff --git a/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php b/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php index 60e8a5e468..f6c9474255 100644 --- a/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php +++ b/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php @@ -82,7 +82,7 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO { return $this->getRawEmailAddresses(idx($this->headers, 'to')); } - public function loadExcludeMailRecipientPHIDs() { + public function loadAllRecipientPHIDs() { $addresses = array_merge( $this->getToAddresses(), $this->getCCAddresses()); diff --git a/src/applications/owners/config/PhabricatorOwnersConfigOptions.php b/src/applications/owners/config/PhabricatorOwnersConfigOptions.php index 7d7b3e958d..5c5766a43a 100644 --- a/src/applications/owners/config/PhabricatorOwnersConfigOptions.php +++ b/src/applications/owners/config/PhabricatorOwnersConfigOptions.php @@ -20,9 +20,35 @@ final class PhabricatorOwnersConfigOptions } public function getOptions() { + $custom_field_type = 'custom:PhabricatorCustomFieldConfigOptionType'; + $default_fields = array(); + + $field_base_class = id(new PhabricatorOwnersPackage()) + ->getCustomFieldBaseClass(); + + $fields_example = array( + 'mycompany:lore' => array( + 'name' => pht('Package Lore'), + 'type' => 'remarkup', + 'caption' => pht('Tales of adventure for this package.'), + ), + ); + $fields_example = id(new PhutilJSON())->encodeFormatted($fields_example); + return array( $this->newOption('metamta.package.subject-prefix', 'string', '[Package]') ->setDescription(pht('Subject prefix for Owners email.')), + $this->newOption('owners.fields', $custom_field_type, $default_fields) + ->setCustomData($field_base_class) + ->setDescription(pht('Select and reorder package fields.')), + $this->newOption('owners.custom-field-definitions', 'wild', array()) + ->setSummary(pht('Custom Owners fields.')) + ->setDescription( + pht( + 'Map of custom fields for Owners packages. For details on '. + 'adding custom fields to Owners, see "Configuring Custom '. + 'Fields" in the documentation.')) + ->addExample($fields_example, pht('Valid Setting')), ); } diff --git a/src/applications/owners/controller/PhabricatorOwnersDetailController.php b/src/applications/owners/controller/PhabricatorOwnersDetailController.php index 19f305dc09..7edcf010b6 100644 --- a/src/applications/owners/controller/PhabricatorOwnersDetailController.php +++ b/src/applications/owners/controller/PhabricatorOwnersDetailController.php @@ -37,8 +37,15 @@ final class PhabricatorOwnersDetailController $repositories = array(); } + $field_list = PhabricatorCustomField::getObjectFields( + $package, + PhabricatorCustomField::ROLE_VIEW); + $field_list + ->setViewer($viewer) + ->readFieldsFromStorage($package); + $actions = $this->buildPackageActionView($package); - $properties = $this->buildPackagePropertyView($package); + $properties = $this->buildPackagePropertyView($package, $field_list); $properties->setActionList($actions); if ($package->isArchived()) { @@ -156,7 +163,10 @@ final class PhabricatorOwnersDetailController } - private function buildPackagePropertyView(PhabricatorOwnersPackage $package) { + private function buildPackagePropertyView( + PhabricatorOwnersPackage $package, + PhabricatorCustomFieldList $field_list) { + $viewer = $this->getViewer(); $view = id(new PHUIPropertyListView()) @@ -187,6 +197,13 @@ final class PhabricatorOwnersDetailController $viewer)); } + $view->invokeWillRenderEvent(); + + $field_list->appendFieldsToPropertyList( + $package, + $viewer, + $view); + return $view; } diff --git a/src/applications/owners/controller/PhabricatorOwnersEditController.php b/src/applications/owners/controller/PhabricatorOwnersEditController.php index af5ae29be8..277e922129 100644 --- a/src/applications/owners/controller/PhabricatorOwnersEditController.php +++ b/src/applications/owners/controller/PhabricatorOwnersEditController.php @@ -36,6 +36,11 @@ final class PhabricatorOwnersEditController $v_description = $package->getDescription(); $v_status = $package->getStatus(); + $field_list = PhabricatorCustomField::getObjectFields( + $package, + PhabricatorCustomField::ROLE_EDIT); + $field_list->setViewer($viewer); + $field_list->readFieldsFromStorage($package); $errors = array(); if ($request->isFormPost()) { @@ -75,6 +80,12 @@ final class PhabricatorOwnersEditController ->setNewValue($v_status); } + $field_xactions = $field_list->buildFieldTransactionsFromRequest( + new PhabricatorOwnersPackageTransaction(), + $request); + + $xactions = array_merge($xactions, $field_xactions); + $editor = id(new PhabricatorOwnersPackageTransactionEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) @@ -126,41 +137,44 @@ final class PhabricatorOwnersEditController ->setName('owners') ->setValue($v_owners)); - if (!$is_new) { - $form->appendChild( - id(new AphrontFormSelectControl()) - ->setLabel(pht('Status')) - ->setName('status') - ->setValue($v_status) - ->setOptions($package->getStatusNameMap())); - } - + if (!$is_new) { $form->appendChild( id(new AphrontFormSelectControl()) - ->setName('auditing') - ->setLabel(pht('Auditing')) - ->setCaption( - pht( - 'With auditing enabled, all future commits that touch '. - 'this package will be reviewed to make sure an owner '. - 'of the package is involved and the commit message has '. - 'a valid revision, reviewed by, and author.')) - ->setOptions( - array( - 'disabled' => pht('Disabled'), - 'enabled' => pht('Enabled'), - )) - ->setValue(($v_auditing ? 'enabled' : 'disabled'))) + ->setLabel(pht('Status')) + ->setName('status') + ->setValue($v_status) + ->setOptions($package->getStatusNameMap())); + } + + $form->appendChild( + id(new AphrontFormSelectControl()) + ->setName('auditing') + ->setLabel(pht('Auditing')) + ->setCaption( + pht( + 'With auditing enabled, all future commits that touch '. + 'this package will be reviewed to make sure an owner '. + 'of the package is involved and the commit message has '. + 'a valid revision, reviewed by, and author.')) + ->setOptions( + array( + 'disabled' => pht('Disabled'), + 'enabled' => pht('Enabled'), + )) + ->setValue(($v_auditing ? 'enabled' : 'disabled'))) ->appendChild( id(new PhabricatorRemarkupControl()) ->setUser($viewer) ->setLabel(pht('Description')) ->setName('description') - ->setValue($v_description)) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->addCancelButton($cancel_uri) - ->setValue($button_text)); + ->setValue($v_description)); + + $field_list->appendFieldsToForm($form); + + $form->appendChild( + id(new AphrontFormSubmitControl()) + ->addCancelButton($cancel_uri) + ->setValue($button_text)); $form_box = id(new PHUIObjectBoxView()) ->setHeaderText($title) diff --git a/src/applications/owners/customfield/PhabricatorOwnersConfiguredCustomField.php b/src/applications/owners/customfield/PhabricatorOwnersConfiguredCustomField.php new file mode 100644 index 0000000000..a35296311f --- /dev/null +++ b/src/applications/owners/customfield/PhabricatorOwnersConfiguredCustomField.php @@ -0,0 +1,23 @@ +assertAttached($this->customFields); + } + + public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) { + $this->customFields = $fields; + return $this; + } + } diff --git a/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php b/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php index d725148771..41f6dbfa0f 100644 --- a/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php +++ b/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php @@ -430,7 +430,8 @@ final class PhabricatorRepositoryPullEngine $path = $repository->getLocalPath(); // This is a local command, but needs credentials. - $future = $repository->getRemoteCommandFuture('pull -u'); + $remote = $repository->getRemoteURIEnvelope(); + $future = $repository->getRemoteCommandFuture('pull -u -- %P', $remote); $future->setCWD($path); try { diff --git a/src/applications/transactions/replyhandler/PhabricatorApplicationTransactionReplyHandler.php b/src/applications/transactions/replyhandler/PhabricatorApplicationTransactionReplyHandler.php index 82f3eca2cc..560a750f00 100644 --- a/src/applications/transactions/replyhandler/PhabricatorApplicationTransactionReplyHandler.php +++ b/src/applications/transactions/replyhandler/PhabricatorApplicationTransactionReplyHandler.php @@ -39,7 +39,7 @@ abstract class PhabricatorApplicationTransactionReplyHandler return $editor; } - private function newTransaction() { + protected function newTransaction() { return $this->getMailReceiver()->getApplicationTransactionTemplate(); } @@ -80,15 +80,15 @@ abstract class PhabricatorApplicationTransactionReplyHandler $xactions = $this->didReceiveMail($mail, $body); // If this object is subscribable, subscribe all the users who were - // CC'd on the message. + // recipients on the message. if ($object instanceof PhabricatorSubscribableInterface) { - $subscriber_phids = $mail->loadCCPHIDs(); + $subscriber_phids = $mail->loadAllRecipientPHIDs(); if ($subscriber_phids) { $xactions[] = $this->newTransaction() ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS) ->setNewValue( array( - '+' => array($viewer->getPHID()), + '+' => $subscriber_phids, )); } } diff --git a/src/docs/user/configuration/custom_fields.diviner b/src/docs/user/configuration/custom_fields.diviner index 41adfbd092..6643a0518f 100644 --- a/src/docs/user/configuration/custom_fields.diviner +++ b/src/docs/user/configuration/custom_fields.diviner @@ -16,11 +16,12 @@ These applications currently support custom fields: | Application | Support | |-------------|---------| -| Maniphest | Full Support | -| Projects | Full Support | -| People | Full Support | | Differential | Partial Support | | Diffusion | Limited Support | +| Maniphest | Full Support | +| Owners | Full Support | +| People | Full Support | +| Projects | Full Support | Custom fields can appear in many interfaces and support search, editing, and other features. @@ -38,11 +39,12 @@ The relevant configuration settings are: | Application | Add Fields | Select Fields | |-------------|------------|---------------| -| Maniphest | `maniphest.custom-field-definitions` | `maniphest.fields` | -| Projects | `projects.custom-field-definitions` | `projects.fields` | -| People | `user.custom-field-definitions` | `user.fields` | | Differential | Planned | `differential.fields` | | Diffusion | Planned | Planned | +| Maniphest | `maniphest.custom-field-definitions` | `maniphest.fields` | +| Owners | `owners.custom-field-definitions` | `owners.fields` | +| People | `user.custom-field-definitions` | `user.fields` | +| Projects | `projects.custom-field-definitions` | `projects.fields` | When adding fields, you'll specify a JSON blob like this (for example, as the value of `maniphest.custom-field-definitions`): @@ -157,11 +159,12 @@ want to add a field to: | Application | Extend | |-------------|---------| -| Maniphest | @{class:ManiphestCustomField} | -| Projects | @{class:PhabricatorProjectCustomField} | -| People | @{class:PhabricatorUserCustomField} | | Differential | @{class:DifferentialCustomField} | | Diffusion | @{class:PhabricatorCommitCustomField} | +| Maniphest | @{class:ManiphestCustomField} | +| Owners | @{class:PhabricatorOwnersCustomField} | +| People | @{class:PhabricatorUserCustomField} | +| Projects | @{class:PhabricatorProjectCustomField} | The easiest way to get started is to drop your subclass into `phabricator/src/extensions/`, which should make it immediately available in the diff --git a/src/docs/user/configuration/managing_daemons.diviner b/src/docs/user/configuration/managing_daemons.diviner index d82421496f..b8d102a13d 100644 --- a/src/docs/user/configuration/managing_daemons.diviner +++ b/src/docs/user/configuration/managing_daemons.diviner @@ -109,7 +109,7 @@ This daemon will daemonize and run normally. just those started with `phd start`. If you're writing a restart script, have it launch any custom daemons explicitly after `phd restart`. - You can write your own daemons and manage them with `phd` by extending - @{class:PhabricatorDaemon}. See {article@contributor:Adding New Classes}. + @{class:PhabricatorDaemon}. See @{article@contributor:Adding New Classes}. - See @{article:Diffusion User Guide} for details about tuning the repository daemon. @@ -137,4 +137,4 @@ Continue by: - learning about the repository daemon with @{article:Diffusion User Guide}; or - - writing your own daemons with {article@contributor:Adding New Classes}. + - writing your own daemons with @{article@contributor:Adding New Classes}. diff --git a/src/infrastructure/diff/PhabricatorInlineCommentController.php b/src/infrastructure/diff/PhabricatorInlineCommentController.php index fd847b5aca..aa37d29c72 100644 --- a/src/infrastructure/diff/PhabricatorInlineCommentController.php +++ b/src/infrastructure/diff/PhabricatorInlineCommentController.php @@ -94,6 +94,19 @@ abstract class PhabricatorInlineCommentController $op = $this->getOperation(); switch ($op) { + case 'busy': + if ($request->isFormPost()) { + return new AphrontAjaxResponse(); + } + + return $this->newDialog() + ->setTitle(pht('Already Editing')) + ->appendParagraph( + pht( + 'You are already editing an inline comment. Finish editing '. + 'your current comment before adding new comments.')) + ->addCancelButton('/') + ->addSubmitButton(pht('Jump to Inline')); case 'hide': case 'show': if (!$request->validateCSRF()) { diff --git a/src/infrastructure/diff/view/PHUIDiffTableOfContentsListView.php b/src/infrastructure/diff/view/PHUIDiffTableOfContentsListView.php index c24acf7bb0..f54b6f3fd7 100644 --- a/src/infrastructure/diff/view/PHUIDiffTableOfContentsListView.php +++ b/src/infrastructure/diff/view/PHUIDiffTableOfContentsListView.php @@ -107,7 +107,7 @@ final class PHUIDiffTableOfContentsListView extends AphrontView { )) ->setColumnClasses( array( - 'center', + null, 'differential-toc-char center', 'differential-toc-prop center', 'differential-toc-ftype center', diff --git a/webroot/rsrc/css/aphront/list-filter-view.css b/webroot/rsrc/css/aphront/list-filter-view.css index f41008cb34..50d43f2383 100644 --- a/webroot/rsrc/css/aphront/list-filter-view.css +++ b/webroot/rsrc/css/aphront/list-filter-view.css @@ -39,7 +39,7 @@ padding: 0 0 4px 4px; } -/* When a list filter view contains two consecuitive forms, lay them out +/* When a list filter view contains two consecutive forms, lay them out without much white space in between them so they look more contiugous. At the time of writing, this is used only in the Diffusion repository search UI. */ diff --git a/webroot/rsrc/css/aphront/table-view.css b/webroot/rsrc/css/aphront/table-view.css index d26a8268c5..8b31b33b8d 100644 --- a/webroot/rsrc/css/aphront/table-view.css +++ b/webroot/rsrc/css/aphront/table-view.css @@ -175,6 +175,10 @@ th.aphront-table-view-sortable-selected { text-align: right; } +.aphront-table-view td.nudgeright, .aphront-table-view th.nudgeright { + padding-right: 0; +} + .aphront-table-view td.wrap { white-space: normal; } @@ -194,6 +198,8 @@ th.aphront-table-view-sortable-selected { padding: 0px; } + + div.single-display-line-bounds { width: 100%; position: relative; diff --git a/webroot/rsrc/css/application/diffusion/diffusion-icons.css b/webroot/rsrc/css/application/diffusion/diffusion-icons.css index b472283001..087ce9362e 100644 --- a/webroot/rsrc/css/application/diffusion/diffusion-icons.css +++ b/webroot/rsrc/css/application/diffusion/diffusion-icons.css @@ -2,31 +2,6 @@ * @provides diffusion-icons-css */ -.diffusion-path-icon { - display: block; - padding-left: 28px; - background-repeat: no-repeat; - background-position: 1px 1px; - height: 18px; - padding-top: 1px; -} - -.diffusion-path-icon-ext { - background-image: url(/rsrc/image/icon/fatcow/folder_go.png); -} - -.diffusion-path-icon-dir { - background-image: url(/rsrc/image/icon/fatcow/folder.png); -} - -.diffusion-path-icon-file { - background-image: url(/rsrc/image/icon/fatcow/page_white_text.png); -} - -.diffusion-path-icon-link { - background-image: url(/rsrc/image/icon/fatcow/page_white_link.png); -} - input.diffusion-clone-uri { display: block; width: 100%; @@ -37,3 +12,11 @@ input.diffusion-clone-uri { text-align: right; color: {$lightgreytext}; } + +.diffusion-browse-name { + margin-left: 8px; +} + +.diffusion-link-icon + .diffusion-link-icon { + margin-left: 6px; +} diff --git a/webroot/rsrc/css/core/remarkup.css b/webroot/rsrc/css/core/remarkup.css index 207b69618c..9a3906f3b8 100644 --- a/webroot/rsrc/css/core/remarkup.css +++ b/webroot/rsrc/css/core/remarkup.css @@ -339,12 +339,13 @@ border-spacing: 1px; background: {$lightblueborder}; margin: 12px 0; + word-break: normal; } .phabricator-remarkup table.remarkup-table th { font-weight: bold; padding: 4px 6px; - background: #F8F9FC; + background: {$lightbluebackground}; } .phabricator-remarkup table.remarkup-table td { diff --git a/webroot/rsrc/image/icon/fatcow/folder.png b/webroot/rsrc/image/icon/fatcow/folder.png deleted file mode 100644 index f1ed9abe03..0000000000 Binary files a/webroot/rsrc/image/icon/fatcow/folder.png and /dev/null differ diff --git a/webroot/rsrc/image/icon/fatcow/folder_go.png b/webroot/rsrc/image/icon/fatcow/folder_go.png deleted file mode 100644 index 3c36ef0c95..0000000000 Binary files a/webroot/rsrc/image/icon/fatcow/folder_go.png and /dev/null differ diff --git a/webroot/rsrc/image/icon/fatcow/page_white_link.png b/webroot/rsrc/image/icon/fatcow/page_white_link.png deleted file mode 100644 index fcb5f80f7f..0000000000 Binary files a/webroot/rsrc/image/icon/fatcow/page_white_link.png and /dev/null differ diff --git a/webroot/rsrc/image/icon/fatcow/page_white_text.png b/webroot/rsrc/image/icon/fatcow/page_white_text.png deleted file mode 100644 index f64dd01170..0000000000 Binary files a/webroot/rsrc/image/icon/fatcow/page_white_text.png and /dev/null differ diff --git a/webroot/rsrc/js/application/differential/DifferentialInlineCommentEditor.js b/webroot/rsrc/js/application/differential/DifferentialInlineCommentEditor.js index 9842da11f5..8defff554d 100644 --- a/webroot/rsrc/js/application/differential/DifferentialInlineCommentEditor.js +++ b/webroot/rsrc/js/application/differential/DifferentialInlineCommentEditor.js @@ -250,12 +250,30 @@ JX.install('DifferentialInlineCommentEditor', { JX.DifferentialInlineCommentEditor._undoRows = rows; }, - start : function() { - this._registerUndoListener(); + _onBusyWorkflow: function() { + // If the user clicks the "Jump to Inline" button, scroll to the row + // being edited. + JX.DOM.scrollTo(this.getRow()); + }, - var data = this._buildRequestData(); + start : function() { var op = this.getOperation(); + // The user is already editing a comment, we're going to give them an + // error message. + if (op == 'busy') { + var onbusy = JX.bind(this, this._onBusyWorkflow); + + new JX.Workflow(this._uri, {op: op}) + .setHandler(onbusy) + .start(); + + return this; + } + + this._registerUndoListener(); + var data = this._buildRequestData(); + if (op == 'delete' || op == 'refdelete' || op == 'undelete') { this._setRowState('loading'); diff --git a/webroot/rsrc/js/application/differential/behavior-edit-inline-comments.js b/webroot/rsrc/js/application/differential/behavior-edit-inline-comments.js index 821d279f50..aac66d66b7 100644 --- a/webroot/rsrc/js/application/differential/behavior-edit-inline-comments.js +++ b/webroot/rsrc/js/application/differential/behavior-edit-inline-comments.js @@ -138,13 +138,23 @@ JX.behavior('differential-edit-inline-comments', function(config) { 'mousedown', ['differential-changeset', 'tag:th'], function(e) { - if (editor || - selecting || - e.isRightButton() || + if (e.isRightButton() || getRowNumber(e.getTarget()) === undefined) { return; } + if (editor) { + new JX.DifferentialInlineCommentEditor(config.uri) + .setOperation('busy') + .setRow(editor.getRow().previousSibling) + .start(); + return; + } + + if (selecting) { + return; + } + selecting = true; root = e.getNode('differential-changeset'); diff --git a/webroot/rsrc/js/core/DragAndDropFileUpload.js b/webroot/rsrc/js/core/DragAndDropFileUpload.js index f457b3540c..cee617061c 100644 --- a/webroot/rsrc/js/core/DragAndDropFileUpload.js +++ b/webroot/rsrc/js/core/DragAndDropFileUpload.js @@ -230,6 +230,8 @@ JX.install('PhabricatorDragAndDropFileUpload', { .setStatus('allocate') .update(); + this.invoke('willUpload', file); + var alloc_uri = this._getUploadURI(file) .setQueryParam('allocate', 1);