From 36e53fd5d0104b7206068d64398b7b040c1a0934 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Fri, 13 Jan 2017 14:07:44 -0800 Subject: [PATCH 01/31] Remove collapsable option from ProfileMenu Summary: Never really used this to full potential and takes up a lot of code and space. Remove option for now and make all profile nav menus small by default. Test Plan: Review user, project, workboard. Set new menus. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T5867 Differential Revision: https://secure.phabricator.com/D17206 --- resources/celerity/map.php | 17 +- src/__phutil_library_map__.php | 2 - .../engine/PhabricatorProfileMenuEngine.php | 72 -------- ...PhabricatorProfileMenuCollapsedSetting.php | 12 -- webroot/rsrc/css/phui/phui-profile-menu.css | 160 ++---------------- .../css/phui/workboards/phui-workboard.css | 5 - .../js/phui/behavior-phui-profile-menu.js | 53 ------ 7 files changed, 15 insertions(+), 306 deletions(-) delete mode 100644 src/applications/settings/setting/PhabricatorProfileMenuCollapsedSetting.php delete mode 100644 webroot/rsrc/js/phui/behavior-phui-profile-menu.js diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 2eeba419ee..07cbaa8725 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => '0b64e988', 'conpherence.pkg.js' => '6249a1cf', - 'core.pkg.css' => '9c725fa0', + 'core.pkg.css' => '1afa1d13', 'core.pkg.js' => 'a2ead3fe', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '9535a7e6', @@ -162,7 +162,7 @@ return array( 'rsrc/css/phui/phui-object-box.css' => '6b487c57', 'rsrc/css/phui/phui-pager.css' => 'bea33d23', 'rsrc/css/phui/phui-pinboard-view.css' => '2495140e', - 'rsrc/css/phui/phui-profile-menu.css' => '4768721a', + 'rsrc/css/phui/phui-profile-menu.css' => 'c71ecdcd', 'rsrc/css/phui/phui-property-list-view.css' => '6d8e58ac', 'rsrc/css/phui/phui-remarkup-preview.css' => '1a8f2591', 'rsrc/css/phui/phui-segment-bar-view.css' => '46342871', @@ -172,7 +172,7 @@ return array( 'rsrc/css/phui/phui-timeline-view.css' => 'bc523970', 'rsrc/css/phui/phui-two-column-view.css' => '7babf5b9', 'rsrc/css/phui/workboards/phui-workboard-color.css' => 'b60ef38a', - 'rsrc/css/phui/workboards/phui-workboard.css' => '16441d5e', + 'rsrc/css/phui/workboards/phui-workboard.css' => 'c88912ee', 'rsrc/css/phui/workboards/phui-workcard.css' => '00979e40', 'rsrc/css/phui/workboards/phui-workpanel.css' => 'a3a63478', 'rsrc/css/sprite-login.css' => '587d92d7', @@ -535,7 +535,6 @@ return array( 'rsrc/js/core/phtize.js' => 'd254d646', 'rsrc/js/phui/behavior-phui-dropdown-menu.js' => '1aa4c968', 'rsrc/js/phui/behavior-phui-file-upload.js' => 'b003d4fb', - 'rsrc/js/phui/behavior-phui-profile-menu.js' => '12884df9', 'rsrc/js/phui/behavior-phui-submenu.js' => 'a6f7a73b', 'rsrc/js/phui/behavior-phui-tab-group.js' => '0a0b10e9', 'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8', @@ -690,7 +689,6 @@ return array( 'javelin-behavior-phui-dropdown-menu' => '1aa4c968', 'javelin-behavior-phui-file-upload' => 'b003d4fb', 'javelin-behavior-phui-hovercards' => 'bcaccd64', - 'javelin-behavior-phui-profile-menu' => '12884df9', 'javelin-behavior-phui-submenu' => 'a6f7a73b', 'javelin-behavior-phui-tab-group' => '0a0b10e9', 'javelin-behavior-policy-control' => 'd0c516d5', @@ -883,7 +881,7 @@ return array( 'phui-oi-simple-ui-css' => 'a8beebea', 'phui-pager-css' => 'bea33d23', 'phui-pinboard-view-css' => '2495140e', - 'phui-profile-menu-css' => '4768721a', + 'phui-profile-menu-css' => 'c71ecdcd', 'phui-property-list-view-css' => '6d8e58ac', 'phui-remarkup-preview-css' => '1a8f2591', 'phui-segment-bar-view-css' => '46342871', @@ -894,7 +892,7 @@ return array( 'phui-timeline-view-css' => 'bc523970', 'phui-two-column-view-css' => '7babf5b9', 'phui-workboard-color-css' => 'b60ef38a', - 'phui-workboard-view-css' => '16441d5e', + 'phui-workboard-view-css' => 'c88912ee', 'phui-workcard-view-css' => '00979e40', 'phui-workpanel-view-css' => 'a3a63478', 'phuix-action-list-view' => 'b5c256b8', @@ -1030,11 +1028,6 @@ return array( 'javelin-dom', 'javelin-typeahead-normalizer', ), - '12884df9' => array( - 'javelin-behavior', - 'javelin-stratcom', - 'javelin-dom', - ), '13c739ea' => array( 'javelin-behavior', 'javelin-stratcom', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 617365f333..76144781ad 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3422,7 +3422,6 @@ phutil_register_library_map(array( 'PhabricatorPolicyTestObject' => 'applications/policy/__tests__/PhabricatorPolicyTestObject.php', 'PhabricatorPolicyType' => 'applications/policy/constants/PhabricatorPolicyType.php', 'PhabricatorPonderApplication' => 'applications/ponder/application/PhabricatorPonderApplication.php', - 'PhabricatorProfileMenuCollapsedSetting' => 'applications/settings/setting/PhabricatorProfileMenuCollapsedSetting.php', 'PhabricatorProfileMenuEditEngine' => 'applications/search/editor/PhabricatorProfileMenuEditEngine.php', 'PhabricatorProfileMenuEditor' => 'applications/search/editor/PhabricatorProfileMenuEditor.php', 'PhabricatorProfileMenuEngine' => 'applications/search/engine/PhabricatorProfileMenuEngine.php', @@ -8575,7 +8574,6 @@ phutil_register_library_map(array( ), 'PhabricatorPolicyType' => 'PhabricatorPolicyConstants', 'PhabricatorPonderApplication' => 'PhabricatorApplication', - 'PhabricatorProfileMenuCollapsedSetting' => 'PhabricatorInternalSetting', 'PhabricatorProfileMenuEditEngine' => 'PhabricatorEditEngine', 'PhabricatorProfileMenuEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorProfileMenuEngine' => 'Phobject', diff --git a/src/applications/search/engine/PhabricatorProfileMenuEngine.php b/src/applications/search/engine/PhabricatorProfileMenuEngine.php index c1d4df3b2a..34b02413a4 100644 --- a/src/applications/search/engine/PhabricatorProfileMenuEngine.php +++ b/src/applications/search/engine/PhabricatorProfileMenuEngine.php @@ -239,11 +239,6 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { } } - $more_items = $this->newAutomaticMenuItems($nav); - foreach ($more_items as $item) { - $nav->addMenuItem($item); - } - $nav->selectFilter(null); $this->navigation = $nav; @@ -410,73 +405,6 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { } } - private function newAutomaticMenuItems(AphrontSideNavFilterView $nav) { - $items = array(); - - // NOTE: We're adding a spacer item for the fixed footer, so that if the - // menu taller than the page content you can still scroll down the page far - // enough to access the last item without the content being obscured by the - // fixed items. - $items[] = id(new PHUIListItemView()) - ->setHideInApplicationMenu(true) - ->addClass('phui-profile-menu-spacer'); - - $collapse_id = celerity_generate_unique_node_id(); - $viewer = $this->getViewer(); - $collapse_key = PhabricatorProfileMenuCollapsedSetting::SETTINGKEY; - - $is_collapsed = $viewer->getUserSetting($collapse_key); - - if ($is_collapsed) { - $nav->addClass('phui-profile-menu-collapsed'); - } else { - $nav->addClass('phui-profile-menu-expanded'); - } - - if ($viewer->isLoggedIn()) { - $settings_uri = '/settings/adjust/?key='.$collapse_key; - } else { - $settings_uri = null; - } - - Javelin::initBehavior( - 'phui-profile-menu', - array( - 'menuID' => $nav->getMainID(), - 'collapseID' => $collapse_id, - 'isCollapsed' => (bool)$is_collapsed, - 'settingsURI' => $settings_uri, - )); - - $collapse_icon = id(new PHUIIconCircleView()) - ->addClass('phui-list-item-icon') - ->addClass('phui-profile-menu-visible-when-expanded') - ->setIcon('fa-chevron-left'); - - $expand_icon = id(new PHUIIconCircleView()) - ->addClass('phui-list-item-icon') - ->addClass('phui-profile-menu-visible-when-collapsed') - ->addSigil('has-tooltip') - ->setMetadata( - array( - 'tip' => pht('Expand'), - 'align' => 'E', - )) - ->setIcon('fa-chevron-right'); - - $items[] = id(new PHUIListItemView()) - ->setName('Collapse') - ->addIcon($collapse_icon) - ->addIcon($expand_icon) - ->setID($collapse_id) - ->addClass('phui-profile-menu-footer') - ->addClass('phui-profile-menu-footer-1') - ->setHideInApplicationMenu(true) - ->setHref('#'); - - return $items; - } - public function getConfigureURI() { return $this->getItemURI('configure/'); } diff --git a/src/applications/settings/setting/PhabricatorProfileMenuCollapsedSetting.php b/src/applications/settings/setting/PhabricatorProfileMenuCollapsedSetting.php deleted file mode 100644 index e98cb85fa6..0000000000 --- a/src/applications/settings/setting/PhabricatorProfileMenuCollapsedSetting.php +++ /dev/null @@ -1,12 +0,0 @@ - Date: Fri, 13 Jan 2017 15:05:39 -0800 Subject: [PATCH 02/31] Remove some remnants of the old ways commit mesage fields worked from Differential Summary: Ref T11114. Ref T12085. I missed a few pieces of cleanup when moving all this stuff over. In particular, load all fields which use Custom Field storage before doing commit-message-related stuff, instead of just the ones that claim they appear on commit messages. Test Plan: Edited revisions and made API calls without apparent issues. See followup on T12085, shortly. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12085, T11114 Differential Revision: https://secure.phabricator.com/D17207 --- ...entialGetCommitMessageConduitAPIMethod.php | 4 +- .../customfield/DifferentialAuditorsField.php | 4 - .../DifferentialBlameRevisionField.php | 4 - .../DifferentialCoreCustomField.php | 9 -- .../customfield/DifferentialCustomField.php | 137 ------------------ .../DifferentialJIRAIssuesField.php | 33 ----- .../DifferentialRevertPlanField.php | 8 - .../DifferentialCommitMessageCustomField.php | 2 +- 8 files changed, 4 insertions(+), 197 deletions(-) diff --git a/src/applications/differential/conduit/DifferentialGetCommitMessageConduitAPIMethod.php b/src/applications/differential/conduit/DifferentialGetCommitMessageConduitAPIMethod.php index 2c5c936679..d45fc22fd3 100644 --- a/src/applications/differential/conduit/DifferentialGetCommitMessageConduitAPIMethod.php +++ b/src/applications/differential/conduit/DifferentialGetCommitMessageConduitAPIMethod.php @@ -142,9 +142,11 @@ final class DifferentialGetCommitMessageConduitAPIMethod private function loadCustomFieldStorage( PhabricatorUser $viewer, DifferentialRevision $revision) { + $custom_field_list = PhabricatorCustomField::getObjectFields( $revision, - DifferentialCustomField::ROLE_COMMITMESSAGE); + PhabricatorCustomField::ROLE_STORAGE); + $custom_field_list ->setViewer($viewer) ->readFieldsFromStorage($revision); diff --git a/src/applications/differential/customfield/DifferentialAuditorsField.php b/src/applications/differential/customfield/DifferentialAuditorsField.php index 544f238458..23055461e0 100644 --- a/src/applications/differential/customfield/DifferentialAuditorsField.php +++ b/src/applications/differential/customfield/DifferentialAuditorsField.php @@ -36,10 +36,6 @@ final class DifferentialAuditorsField return true; } - public function shouldAppearInCommitMessage() { - return true; - } - public function shouldAppearInConduitTransactions() { return true; } diff --git a/src/applications/differential/customfield/DifferentialBlameRevisionField.php b/src/applications/differential/customfield/DifferentialBlameRevisionField.php index b2d8872225..d36e199b1a 100644 --- a/src/applications/differential/customfield/DifferentialBlameRevisionField.php +++ b/src/applications/differential/customfield/DifferentialBlameRevisionField.php @@ -91,10 +91,6 @@ final class DifferentialBlameRevisionField $xaction->renderHandleLink($object_phid)); } - public function shouldAppearInCommitMessage() { - return true; - } - public function shouldAppearInConduitDictionary() { return true; } diff --git a/src/applications/differential/customfield/DifferentialCoreCustomField.php b/src/applications/differential/customfield/DifferentialCoreCustomField.php index d4181a31e7..6d956ac367 100644 --- a/src/applications/differential/customfield/DifferentialCoreCustomField.php +++ b/src/applications/differential/customfield/DifferentialCoreCustomField.php @@ -156,15 +156,6 @@ abstract class DifferentialCoreCustomField return $this->value; } - public function readValueFromCommitMessage($value) { - $this->setValue($value); - return $this; - } - - public function renderCommitMessageValue(array $handles) { - return $this->getValue(); - } - public function getConduitDictionaryValue() { return $this->getValue(); } diff --git a/src/applications/differential/customfield/DifferentialCustomField.php b/src/applications/differential/customfield/DifferentialCustomField.php index f210dd0f63..487e412f66 100644 --- a/src/applications/differential/customfield/DifferentialCustomField.php +++ b/src/applications/differential/customfield/DifferentialCustomField.php @@ -7,9 +7,6 @@ abstract class DifferentialCustomField extends PhabricatorCustomField { - const ROLE_COMMITMESSAGE = 'differential:commitmessage'; - const ROLE_COMMITMESSAGEEDIT = 'differential:commitmessageedit'; - /** * TODO: It would be nice to remove this, but a lot of different code is * bound together by it. Until everything is modernized, retaining the old @@ -25,18 +22,6 @@ abstract class DifferentialCustomField return $this->getFieldKeyForConduit(); } - public function shouldEnableForRole($role) { - switch ($role) { - case self::ROLE_COMMITMESSAGE: - return $this->shouldAppearInCommitMessage(); - case self::ROLE_COMMITMESSAGEEDIT: - return $this->shouldAppearInCommitMessage() && - $this->shouldAllowEditInCommitMessage(); - } - - return parent::shouldEnableForRole($role); - } - protected function parseObjectList( $value, array $types, @@ -97,39 +82,6 @@ abstract class DifferentialCustomField /* -( Integration with Commit Messages )----------------------------------- */ - /** - * @task commitmessage - */ - public function shouldAppearInCommitMessage() { - if ($this->getProxy()) { - return $this->getProxy()->shouldAppearInCommitMessage(); - } - return false; - } - - - /** - * @task commitmessage - */ - public function shouldAppearInCommitMessageTemplate() { - if ($this->getProxy()) { - return $this->getProxy()->shouldAppearInCommitMessageTemplate(); - } - return false; - } - - - /** - * @task commitmessage - */ - public function shouldAllowEditInCommitMessage() { - if ($this->getProxy()) { - return $this->getProxy()->shouldAllowEditInCommitMessage(); - } - return true; - } - - /** * @task commitmessage */ @@ -141,95 +93,6 @@ abstract class DifferentialCustomField } - /** - * @task commitmessage - */ - public function getCommitMessageLabels() { - if ($this->getProxy()) { - return $this->getProxy()->getCommitMessageLabels(); - } - return array($this->renderCommitMessageLabel()); - } - - - /** - * @task commitmessage - */ - public function parseValueFromCommitMessage($value) { - if ($this->getProxy()) { - return $this->getProxy()->parseValueFromCommitMessage($value); - } - return $value; - } - - - /** - * @task commitmessage - */ - public function readValueFromCommitMessage($value) { - if ($this->getProxy()) { - $this->getProxy()->readValueFromCommitMessage($value); - return $this; - } - return $this; - } - - - /** - * @task commitmessage - */ - public function shouldOverwriteWhenCommitMessageIsEdited() { - if ($this->getProxy()) { - return $this->getProxy()->shouldOverwriteWhenCommitMessageIsEdited(); - } - return false; - } - - - /** - * @task commitmessage - */ - public function getRequiredHandlePHIDsForCommitMessage() { - if ($this->getProxy()) { - return $this->getProxy()->getRequiredHandlePHIDsForCommitMessage(); - } - return array(); - } - - - /** - * @task commitmessage - */ - public function renderCommitMessageLabel() { - if ($this->getProxy()) { - return $this->getProxy()->renderCommitMessageLabel(); - } - return $this->getFieldName(); - } - - - /** - * @task commitmessage - */ - public function renderCommitMessageValue(array $handles) { - if ($this->getProxy()) { - return $this->getProxy()->renderCommitMessageValue($handles); - } - throw new PhabricatorCustomFieldImplementationIncompleteException($this); - } - - - /** - * @task commitmessage - */ - public function validateCommitMessageValue($value) { - if ($this->getProxy()) { - return $this->getProxy()->validateCommitMessageValue($value); - } - return; - } - - /* -( Integration with Diff Properties )----------------------------------- */ diff --git a/src/applications/differential/customfield/DifferentialJIRAIssuesField.php b/src/applications/differential/customfield/DifferentialJIRAIssuesField.php index fc15f4a45b..e97efd6ad5 100644 --- a/src/applications/differential/customfield/DifferentialJIRAIssuesField.php +++ b/src/applications/differential/customfield/DifferentialJIRAIssuesField.php @@ -270,39 +270,6 @@ final class DifferentialJIRAIssuesField $editor->save(); } - public function shouldAppearInCommitMessage() { - return true; - } - - public function shouldAppearInCommitMessageTemplate() { - return true; - } - - public function getCommitMessageLabels() { - return array( - 'JIRA', - 'JIRA Issues', - 'JIRA Issue', - ); - } - - public function parseValueFromCommitMessage($value) { - return preg_split('/[\s,]+/', $value, $limit = -1, PREG_SPLIT_NO_EMPTY); - } - - public function readValueFromCommitMessage($value) { - $this->setValue($value); - return $this; - } - - public function renderCommitMessageValue(array $handles) { - $value = $this->getValue(); - if (!$value) { - return null; - } - return implode(', ', $value); - } - public function shouldAppearInConduitDictionary() { return true; } diff --git a/src/applications/differential/customfield/DifferentialRevertPlanField.php b/src/applications/differential/customfield/DifferentialRevertPlanField.php index 0fd5531426..ca13788294 100644 --- a/src/applications/differential/customfield/DifferentialRevertPlanField.php +++ b/src/applications/differential/customfield/DifferentialRevertPlanField.php @@ -130,14 +130,6 @@ final class DifferentialRevertPlanField return array($xaction->getNewValue()); } - public function shouldAppearInCommitMessage() { - return true; - } - - public function renderCommitMessageValue(array $handles) { - return $this->getValue(); - } - public function shouldAppearInConduitDictionary() { return true; } diff --git a/src/applications/differential/field/DifferentialCommitMessageCustomField.php b/src/applications/differential/field/DifferentialCommitMessageCustomField.php index cfa71a2a58..21f21e1774 100644 --- a/src/applications/differential/field/DifferentialCommitMessageCustomField.php +++ b/src/applications/differential/field/DifferentialCommitMessageCustomField.php @@ -45,7 +45,7 @@ abstract class DifferentialCommitMessageCustomField protected function getCustomFieldOrder($key) { $field_list = PhabricatorCustomField::getObjectFields( new DifferentialRevision(), - DifferentialCustomField::ROLE_COMMITMESSAGE); + PhabricatorCustomField::ROLE_DEFAULT); $fields = $field_list->getFields(); From 903e37a21b50ee8d92fba1b854b508c55ca237e2 Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 14 Jan 2017 09:22:51 -0800 Subject: [PATCH 03/31] Show yellow "draft" bubble in Audit Summary: Fixes T6660. Uses the new stuff in Audit to build an EditEngine-aware icon. Test Plan: {F2364304} Reviewers: chad Reviewed By: chad Maniphest Tasks: T6660 Differential Revision: https://secure.phabricator.com/D17208 --- src/__phutil_library_map__.php | 3 ++ .../query/PhabricatorCommitSearchEngine.php | 6 ++- .../audit/view/PhabricatorAuditListView.php | 32 ++++++++++++++-- .../query/DifferentialRevisionQuery.php | 31 ++-------------- .../engine/DiffusionCommitDraftEngine.php | 18 +++++++++ .../diffusion/query/DiffusionCommitQuery.php | 14 +++++++ .../storage/PhabricatorRepositoryCommit.php | 21 ++++++++++- .../draft/PhabricatorDraftEngine.php | 37 +++++++++++++++++++ .../draft/PhabricatorDraftInterface.php | 21 +++++++++++ 9 files changed, 149 insertions(+), 34 deletions(-) create mode 100644 src/applications/diffusion/engine/DiffusionCommitDraftEngine.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 76144781ad..4083a5aeb8 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -629,6 +629,7 @@ phutil_register_library_map(array( 'DiffusionCommitDiffContentHeraldField' => 'applications/diffusion/herald/DiffusionCommitDiffContentHeraldField.php', 'DiffusionCommitDiffContentRemovedHeraldField' => 'applications/diffusion/herald/DiffusionCommitDiffContentRemovedHeraldField.php', 'DiffusionCommitDiffEnormousHeraldField' => 'applications/diffusion/herald/DiffusionCommitDiffEnormousHeraldField.php', + 'DiffusionCommitDraftEngine' => 'applications/diffusion/engine/DiffusionCommitDraftEngine.php', 'DiffusionCommitEditConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionCommitEditConduitAPIMethod.php', 'DiffusionCommitEditController' => 'applications/diffusion/controller/DiffusionCommitEditController.php', 'DiffusionCommitEditEngine' => 'applications/diffusion/editor/DiffusionCommitEditEngine.php', @@ -5341,6 +5342,7 @@ phutil_register_library_map(array( 'DiffusionCommitDiffContentHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitDiffContentRemovedHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitDiffEnormousHeraldField' => 'DiffusionCommitHeraldField', + 'DiffusionCommitDraftEngine' => 'PhabricatorDraftEngine', 'DiffusionCommitEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'DiffusionCommitEditController' => 'DiffusionController', 'DiffusionCommitEditEngine' => 'PhabricatorEditEngine', @@ -8794,6 +8796,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationTransactionInterface', 'PhabricatorFulltextInterface', 'PhabricatorConduitResultInterface', + 'PhabricatorDraftInterface', ), 'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO', diff --git a/src/applications/audit/query/PhabricatorCommitSearchEngine.php b/src/applications/audit/query/PhabricatorCommitSearchEngine.php index fa4fa3c963..f24b12d2b8 100644 --- a/src/applications/audit/query/PhabricatorCommitSearchEngine.php +++ b/src/applications/audit/query/PhabricatorCommitSearchEngine.php @@ -14,7 +14,8 @@ final class PhabricatorCommitSearchEngine public function newQuery() { return id(new DiffusionCommitQuery()) ->needAuditRequests(true) - ->needCommitData(true); + ->needCommitData(true) + ->needDrafts(true); } protected function newResultBuckets() { @@ -140,7 +141,8 @@ final class PhabricatorCommitSearchEngine $bucket = $this->getResultBucket($query); $template = id(new PhabricatorAuditListView()) - ->setViewer($viewer); + ->setViewer($viewer) + ->setShowDrafts(true); $views = array(); if ($bucket) { diff --git a/src/applications/audit/view/PhabricatorAuditListView.php b/src/applications/audit/view/PhabricatorAuditListView.php index f348acc759..8d4aef61f2 100644 --- a/src/applications/audit/view/PhabricatorAuditListView.php +++ b/src/applications/audit/view/PhabricatorAuditListView.php @@ -4,6 +4,7 @@ final class PhabricatorAuditListView extends AphrontView { private $commits; private $header; + private $showDrafts; private $noDataString; private $highlightedAudits; @@ -25,6 +26,15 @@ final class PhabricatorAuditListView extends AphrontView { return $this->header; } + public function setShowDrafts($show_drafts) { + $this->showDrafts = $show_drafts; + return $this; + } + + public function getShowDrafts() { + return $this->showDrafts; + } + /** * These commits should have both commit data and audit requests attached. */ @@ -75,6 +85,16 @@ final class PhabricatorAuditListView extends AphrontView { $handles = $viewer->loadHandles(mpull($this->commits, 'getPHID')); + $show_drafts = $this->getShowDrafts(); + + $draft_icon = id(new PHUIIconView()) + ->setIcon('fa-comment yellow') + ->addSigil('has-tooltip') + ->setMetadata( + array( + 'tip' => pht('Unsubmitted Comments'), + )); + $list = new PHUIObjectItemListView(); foreach ($this->commits as $commit) { $commit_phid = $commit->getPHID(); @@ -88,7 +108,6 @@ final class PhabricatorAuditListView extends AphrontView { $audits = mpull($commit->getAudits(), null, 'getAuditorPHID'); $auditors = array(); - $reasons = array(); foreach ($audits as $audit) { $auditor_phid = $audit->getAuditorPHID(); $auditors[$auditor_phid] = $viewer->renderHandle($auditor_phid); @@ -114,9 +133,16 @@ final class PhabricatorAuditListView extends AphrontView { $item = id(new PHUIObjectItemView()) ->setObjectName($commit_name) ->setHeader($commit_desc) - ->setHref($commit_link) + ->setHref($commit_link); + + if ($show_drafts) { + if ($commit->getHasDraft($viewer)) { + $item->addAttribute($draft_icon); + } + } + + $item ->addAttribute(pht('Author: %s', $author_name)) - ->addAttribute($reasons) ->addIcon('none', $committed); if (!empty($auditors)) { diff --git a/src/applications/differential/query/DifferentialRevisionQuery.php b/src/applications/differential/query/DifferentialRevisionQuery.php index a4e446ad0d..5dff433e9c 100644 --- a/src/applications/differential/query/DifferentialRevisionQuery.php +++ b/src/applications/differential/query/DifferentialRevisionQuery.php @@ -473,34 +473,9 @@ final class DifferentialRevisionQuery } if ($this->needDrafts) { - $viewer_phid = $viewer->getPHID(); - $draft_type = PhabricatorObjectHasDraftEdgeType::EDGECONST; - - if (!$viewer_phid) { - // Viewers without a valid PHID can never have drafts. - foreach ($revisions as $revision) { - $revision->attachHasDraft($viewer, false); - } - } else { - $edge_query = id(new PhabricatorEdgeQuery()) - ->withSourcePHIDs(mpull($revisions, 'getPHID')) - ->withEdgeTypes( - array( - $draft_type, - )) - ->withDestinationPHIDs(array($viewer_phid)); - - $edge_query->execute(); - - foreach ($revisions as $revision) { - $has_draft = (bool)$edge_query->getDestinationPHIDs( - array( - $revision->getPHID(), - )); - - $revision->attachHasDraft($viewer, $has_draft); - } - } + PhabricatorDraftEngine::attachDrafts( + $viewer, + $revisions); } return $revisions; diff --git a/src/applications/diffusion/engine/DiffusionCommitDraftEngine.php b/src/applications/diffusion/engine/DiffusionCommitDraftEngine.php new file mode 100644 index 0000000000..ce39e525a6 --- /dev/null +++ b/src/applications/diffusion/engine/DiffusionCommitDraftEngine.php @@ -0,0 +1,18 @@ +getViewer(); + $commit = $this->getObject(); + + $inlines = PhabricatorAuditInlineComment::loadDraftComments( + $viewer, + $commit->getPHID(), + $raw = true); + + return (bool)$inlines; + } + +} diff --git a/src/applications/diffusion/query/DiffusionCommitQuery.php b/src/applications/diffusion/query/DiffusionCommitQuery.php index a24f8038e0..fddaf547bd 100644 --- a/src/applications/diffusion/query/DiffusionCommitQuery.php +++ b/src/applications/diffusion/query/DiffusionCommitQuery.php @@ -22,6 +22,7 @@ final class DiffusionCommitQuery private $importing; private $needCommitData; + private $needDrafts; public function withIDs(array $ids) { $this->ids = $ids; @@ -98,6 +99,11 @@ final class DiffusionCommitQuery return $this; } + public function needDrafts($need) { + $this->needDrafts = $need; + return $this; + } + public function needAuditRequests($need) { $this->needAuditRequests = $need; return $this; @@ -239,6 +245,8 @@ final class DiffusionCommitQuery } protected function didFilterPage(array $commits) { + $viewer = $this->getViewer(); + if ($this->needCommitData) { $data = id(new PhabricatorRepositoryCommitData())->loadAllWhere( 'commitID in (%Ld)', @@ -268,6 +276,12 @@ final class DiffusionCommitQuery } } + if ($this->needDrafts) { + PhabricatorDraftEngine::attachDrafts( + $viewer, + $commits); + } + return $commits; } diff --git a/src/applications/repository/storage/PhabricatorRepositoryCommit.php b/src/applications/repository/storage/PhabricatorRepositoryCommit.php index 67f187d9c2..7f617069ec 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryCommit.php +++ b/src/applications/repository/storage/PhabricatorRepositoryCommit.php @@ -14,7 +14,8 @@ final class PhabricatorRepositoryCommit PhabricatorCustomFieldInterface, PhabricatorApplicationTransactionInterface, PhabricatorFulltextInterface, - PhabricatorConduitResultInterface { + PhabricatorConduitResultInterface, + PhabricatorDraftInterface { protected $repositoryID; protected $phid; @@ -39,6 +40,7 @@ final class PhabricatorRepositoryCommit private $audits = self::ATTACHABLE; private $repository = self::ATTACHABLE; private $customFields = self::ATTACHABLE; + private $drafts = array(); public function attachRepository(PhabricatorRepository $repository) { $this->repository = $repository; @@ -342,6 +344,7 @@ final class PhabricatorRepositoryCommit return nonempty($parsed->getDisplayName(), $parsed->getAddress()); } + /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { @@ -603,4 +606,20 @@ final class PhabricatorRepositoryCommit return array(); } + +/* -( PhabricatorDraftInterface )------------------------------------------ */ + + public function newDraftEngine() { + return new DiffusionCommitDraftEngine(); + } + + public function getHasDraft(PhabricatorUser $viewer) { + return $this->assertAttachedKey($this->drafts, $viewer->getCacheFragment()); + } + + public function attachHasDraft(PhabricatorUser $viewer, $has_draft) { + $this->drafts[$viewer->getCacheFragment()] = $has_draft; + return $this; + } + } diff --git a/src/applications/transactions/draft/PhabricatorDraftEngine.php b/src/applications/transactions/draft/PhabricatorDraftEngine.php index 63a9945151..9e55104912 100644 --- a/src/applications/transactions/draft/PhabricatorDraftEngine.php +++ b/src/applications/transactions/draft/PhabricatorDraftEngine.php @@ -95,4 +95,41 @@ abstract class PhabricatorDraftEngine $editor->save(); } + final public static function attachDrafts( + PhabricatorUser $viewer, + array $objects) { + assert_instances_of($objects, 'PhabricatorDraftInterface'); + + $viewer_phid = $viewer->getPHID(); + + if (!$viewer_phid) { + // Viewers without a valid PHID can never have drafts. + foreach ($objects as $object) { + $object->attachHasDraft($viewer, false); + } + return; + } else { + $draft_type = PhabricatorObjectHasDraftEdgeType::EDGECONST; + + $edge_query = id(new PhabricatorEdgeQuery()) + ->withSourcePHIDs(mpull($objects, 'getPHID')) + ->withEdgeTypes( + array( + $draft_type, + )) + ->withDestinationPHIDs(array($viewer_phid)); + + $edge_query->execute(); + + foreach ($objects as $object) { + $has_draft = (bool)$edge_query->getDestinationPHIDs( + array( + $object->getPHID(), + )); + + $object->attachHasDraft($viewer, $has_draft); + } + } + } + } diff --git a/src/applications/transactions/draft/PhabricatorDraftInterface.php b/src/applications/transactions/draft/PhabricatorDraftInterface.php index 69b2edf8a0..2e03c17d50 100644 --- a/src/applications/transactions/draft/PhabricatorDraftInterface.php +++ b/src/applications/transactions/draft/PhabricatorDraftInterface.php @@ -4,4 +4,25 @@ interface PhabricatorDraftInterface { public function newDraftEngine(); + public function getHasDraft(PhabricatorUser $viewer); + public function attachHasDraft(PhabricatorUser $viewer, $has_draft); + } + +/* -( PhabricatorDraftInterface )------------------------------------------ */ +/* + + public function newDraftEngine() { + return new <...>DraftEngine(); + } + + public function getHasDraft(PhabricatorUser $viewer) { + return $this->assertAttachedKey($this->drafts, $viewer->getCacheFragment()); + } + + public function attachHasDraft(PhabricatorUser $viewer, $has_draft) { + $this->drafts[$viewer->getCacheFragment()] = $has_draft; + return $this; + } + +*/ From a4a9485612839072a46e715d1ce47c29eddcb134 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 16 Jan 2017 13:31:04 -0800 Subject: [PATCH 04/31] Hide dropdown menus when users click workflow items Summary: In D16157, dropdown menus got an overly-broad check for not closing when an item is clicked. Specifically, we don't want to close the menu if the item is really opening a submenu, like "Edit Related Objects..." does on mobile. The check for this is too broad, and also doesn't close the menu if the item has workflow. Instead, use a narrower check. Test Plan: - Menu still stays open when toggling submenus like "Edit Related Objects". - Menu now closes properly when using workflow items like "Edit Comment" or "Remove Comment". Reviewers: chad Reviewed By: chad Differential Revision: https://secure.phabricator.com/D17210 --- resources/celerity/map.php | 18 +++++----- src/view/layout/PhabricatorActionView.php | 35 +++++++++++-------- .../js/phui/behavior-phui-dropdown-menu.js | 4 ++- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 07cbaa8725..ac4dd3c2a6 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -10,7 +10,7 @@ return array( 'conpherence.pkg.css' => '0b64e988', 'conpherence.pkg.js' => '6249a1cf', 'core.pkg.css' => '1afa1d13', - 'core.pkg.js' => 'a2ead3fe', + 'core.pkg.js' => '892976d4', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '9535a7e6', 'differential.pkg.js' => 'ddfeb49b', @@ -533,7 +533,7 @@ return array( 'rsrc/js/core/behavior-watch-anchor.js' => '9f36c42d', 'rsrc/js/core/behavior-workflow.js' => '0a3f3021', 'rsrc/js/core/phtize.js' => 'd254d646', - 'rsrc/js/phui/behavior-phui-dropdown-menu.js' => '1aa4c968', + 'rsrc/js/phui/behavior-phui-dropdown-menu.js' => '8744dfd1', 'rsrc/js/phui/behavior-phui-file-upload.js' => 'b003d4fb', 'rsrc/js/phui/behavior-phui-submenu.js' => 'a6f7a73b', 'rsrc/js/phui/behavior-phui-tab-group.js' => '0a0b10e9', @@ -686,7 +686,7 @@ return array( 'javelin-behavior-phabricator-watch-anchor' => '9f36c42d', 'javelin-behavior-pholio-mock-edit' => 'bee502c8', 'javelin-behavior-pholio-mock-view' => 'fbe497e7', - 'javelin-behavior-phui-dropdown-menu' => '1aa4c968', + 'javelin-behavior-phui-dropdown-menu' => '8744dfd1', 'javelin-behavior-phui-file-upload' => 'b003d4fb', 'javelin-behavior-phui-hovercards' => 'bcaccd64', 'javelin-behavior-phui-submenu' => 'a6f7a73b', @@ -1057,12 +1057,6 @@ return array( '19f9369b' => array( 'phui-oi-list-view-css', ), - '1aa4c968' => array( - 'javelin-behavior', - 'javelin-stratcom', - 'javelin-dom', - 'phuix-dropdown-menu', - ), '1ad0a787' => array( 'javelin-install', 'javelin-reactor', @@ -1573,6 +1567,12 @@ return array( 'phabricator-tooltip', 'changeset-view-manager', ), + '8744dfd1' => array( + 'javelin-behavior', + 'javelin-stratcom', + 'javelin-dom', + 'phuix-dropdown-menu', + ), '88236f00' => array( 'javelin-behavior', 'phabricator-keyboard-shortcut', diff --git a/src/view/layout/PhabricatorActionView.php b/src/view/layout/PhabricatorActionView.php index 8788529945..e7e145bee6 100644 --- a/src/view/layout/PhabricatorActionView.php +++ b/src/view/layout/PhabricatorActionView.php @@ -173,22 +173,26 @@ final class PhabricatorActionView extends AphrontView { ->setIcon($this->icon.$color); } + $sigils = array(); + if ($this->workflow) { + $sigils[] = 'workflow'; + } + + if ($this->download) { + $sigils[] = 'download'; + } + + if ($this->submenu) { + $sigils[] = 'keep-open'; + } + + if ($this->sigils) { + $sigils = array_merge($sigils, $this->sigils); + } + + $sigils = $sigils ? implode(' ', $sigils) : null; + if ($this->href) { - - $sigils = array(); - if ($this->workflow) { - $sigils[] = 'workflow'; - } - if ($this->download) { - $sigils[] = 'download'; - } - - if ($this->sigils) { - $sigils = array_merge($sigils, $this->sigils); - } - - $sigils = $sigils ? implode(' ', $sigils) : null; - if ($this->renderAsForm) { if (!$this->hasViewer()) { throw new Exception( @@ -248,6 +252,7 @@ final class PhabricatorActionView extends AphrontView { 'span', array( 'class' => 'phabricator-action-view-item', + 'sigil' => $sigils, ), array($icon, $this->name)); } diff --git a/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js b/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js index 4bde14a307..8c3c9cc09f 100644 --- a/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js +++ b/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js @@ -48,7 +48,9 @@ JX.behavior('phui-dropdown-menu', function() { return; } - if (JX.Stratcom.pass()) { + // If this item opens a submenu, we don't want to close the current + // menu. One submenu is "Edit Related Objects..." on mobile. + if (JX.Stratcom.hasSigil(e.getTarget(), 'keep-open')) { return; } From 48187cdbbe9969d736e07ebacbd75ef7b2f8ff23 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 17 Jan 2017 07:32:18 -0800 Subject: [PATCH 05/31] Fix an unusual nonterminating task graph node Summary: Fixes T12114. There were a couple of bugs here: - We could draw too many joining lines if a node had a parent with multiple descendants. - We could incorrectly ignore columns because of an `unset()`. I //think// this fixes both things without collateral damage. This whole thing is a little hard to understand/debug and has grown beyond its original scope, so I'll probably rewrite it if there are more issues. Test Plan: - Unit tests. - My local repro is clean now: {F2424920} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12114 Differential Revision: https://secure.phabricator.com/D17211 --- .../diff/view/PHUIDiffGraphView.php | 4 +-- .../__tests__/PHUIDiffGraphViewTestCase.php | 33 ++++++++++++++++--- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/infrastructure/diff/view/PHUIDiffGraphView.php b/src/infrastructure/diff/view/PHUIDiffGraphView.php index ed4b0acf57..76ae0b2045 100644 --- a/src/infrastructure/diff/view/PHUIDiffGraphView.php +++ b/src/infrastructure/diff/view/PHUIDiffGraphView.php @@ -50,7 +50,6 @@ final class PHUIDiffGraphView extends Phobject { $thread_count = $pos; for ($n = 0; $n < $thread_count; $n++) { - if (empty($threads[$n])) { $line .= ' '; continue; @@ -60,7 +59,7 @@ final class PHUIDiffGraphView extends Phobject { if ($found) { $line .= ' '; $joins[] = $n; - unset($threads[$n]); + $threads[$n] = false; } else { $line .= 'o'; $found = true; @@ -114,6 +113,7 @@ final class PHUIDiffGraphView extends Phobject { if ($thread_commit == $parent) { $found = true; $splits[] = $idx; + break; } } diff --git a/src/infrastructure/diff/view/__tests__/PHUIDiffGraphViewTestCase.php b/src/infrastructure/diff/view/__tests__/PHUIDiffGraphViewTestCase.php index 9bcf9645a3..2b9e4f8097 100644 --- a/src/infrastructure/diff/view/__tests__/PHUIDiffGraphViewTestCase.php +++ b/src/infrastructure/diff/view/__tests__/PHUIDiffGraphViewTestCase.php @@ -45,10 +45,10 @@ final class PHUIDiffGraphViewTestCase extends PhabricatorTestCase { '^', '|^', 'o ', - '|^', - '||^', - 'o ', - 'x', + '| ^', + '| |^', + 'o ', + 'x ', ); $this->assertGraph($picture, $graph, pht('Reverse Tree')); @@ -71,7 +71,30 @@ final class PHUIDiffGraphViewTestCase extends PhabricatorTestCase { 'x ', ); - $this->assertGraph($picture, $graph, pht('Reverse Tree')); + $this->assertGraph($picture, $graph, pht('Terminated Tree')); + } + + public function testThreeWayGraphJoin() { + $nodes = array( + 'A' => array('D', 'C', 'B'), + 'B' => array('D'), + 'C' => array('B', 'E', 'F'), + 'D' => array(), + 'E' => array(), + 'F' => array(), + ); + + $graph = $this->newGraph($nodes); + $picture = array( + '^', + '||o', + '|o|', + 'x| ||', + ' | x|', + ' | x', + ); + + $this->assertGraph($picture, $graph, pht('Three-Way Tree')); } private function newGraph(array $nodes) { From 23721799fd0b98d1c15f55be524ce4224f18d72e Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 17 Jan 2017 11:24:34 -0800 Subject: [PATCH 06/31] Explicitly warn the user multiple times when they try to register an external account with an existing email Summary: Ref T3472. Ref T12113. This implements the gigantic roadblock nonsense in T3472. Test Plan: {F2425916} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12113, T3472 Differential Revision: https://secure.phabricator.com/D17212 --- .../PhabricatorAuthRegisterController.php | 84 ++++++++++++++++--- 1 file changed, 74 insertions(+), 10 deletions(-) diff --git a/src/applications/auth/controller/PhabricatorAuthRegisterController.php b/src/applications/auth/controller/PhabricatorAuthRegisterController.php index 3e4135fff5..cdb7980a16 100644 --- a/src/applications/auth/controller/PhabricatorAuthRegisterController.php +++ b/src/applications/auth/controller/PhabricatorAuthRegisterController.php @@ -54,6 +54,8 @@ final class PhabricatorAuthRegisterController } } + $errors = array(); + $user = new PhabricatorUser(); $default_username = $account->getUsername(); @@ -65,23 +67,37 @@ final class PhabricatorAuthRegisterController $default_email = $invite->getEmailAddress(); } - if (!PhabricatorUserEmail::isValidAddress($default_email)) { - $default_email = null; + if ($default_email !== null) { + if (!PhabricatorUserEmail::isValidAddress($default_email)) { + $errors[] = pht( + 'The email address associated with this external account ("%s") is '. + 'not a valid email address and can not be used to register a '. + 'Phabricator account. Choose a different, valid address.', + phutil_tag('strong', array(), $default_email)); + $default_email = null; + } } if ($default_email !== null) { // We should bypass policy here becase e.g. limiting an application use // to a subset of users should not allow the others to overwrite - // configured application emails + // configured application emails. $application_email = id(new PhabricatorMetaMTAApplicationEmailQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withAddresses(array($default_email)) ->executeOne(); if ($application_email) { + $errors[] = pht( + 'The email address associated with this account ("%s") is '. + 'already in use by an application and can not be used to '. + 'register a new Phabricator account. Choose a different, valid '. + 'address.', + phutil_tag('strong', array(), $default_email)); $default_email = null; } } + $show_existing = null; if ($default_email !== null) { // If the account source provided an email, but it's not allowed by // the configuration, roadblock the user. Previously, we let the user @@ -105,9 +121,6 @@ final class PhabricatorAuthRegisterController // If the account source provided an email, but another account already // has that email, just pretend we didn't get an email. - - // TODO: See T3472. - if ($default_email !== null) { $same_email = id(new PhabricatorUserEmail())->loadOneWhere( 'address = %s', @@ -118,12 +131,57 @@ final class PhabricatorAuthRegisterController // invite means that the address is nonprimary and unverified and // we're OK to steal it. } else { + $show_existing = $default_email; $default_email = null; } } } } + if ($show_existing !== null) { + if (!$request->getInt('phase')) { + return $this->newDialog() + ->setTitle(pht('Email Address Already in Use')) + ->addHiddenInput('phase', 1) + ->appendParagraph( + pht( + 'You are creating a new Phabricator account linked to an '. + 'existing external account from outside Phabricator.')) + ->appendParagraph( + pht( + 'The email address ("%s") associated with the external account '. + 'is already in use by an existing Phabricator account. Multiple '. + 'Phabricator accounts may not have the same email address, so '. + 'you can not use this email address to register a new '. + 'Phabricator account.', + phutil_tag('strong', array(), $show_existing))) + ->appendParagraph( + pht( + 'If you want to register a new account, continue with this '. + 'registration workflow and choose a new, unique email address '. + 'for the new account.')) + ->appendParagraph( + pht( + 'If you want to link an existing Phabricator account to this '. + 'external account, do not continue. Instead: log in to your '. + 'existing account, then go to "Settings" and link the account '. + 'in the "External Accounts" panel.')) + ->appendParagraph( + pht( + 'If you continue, you will create a new account. You will not '. + 'be able to link this external account to an existing account.')) + ->addCancelButton('/auth/login/', pht('Cancel')) + ->addSubmitButton(pht('Create New Account')); + } else { + $errors[] = pht( + 'The external account you are registering with has an email address '. + 'that is already in use ("%s") by an existing Phabricator account. '. + 'Choose a new, valid email address to register a new Phabricator '. + 'account.', + phutil_tag('strong', array(), $show_existing)); + } + } + $profile = id(new PhabricatorRegistrationProfile()) ->setDefaultUsername($default_username) ->setDefaultEmail($default_email) @@ -167,8 +225,6 @@ final class PhabricatorAuthRegisterController $value_email = $default_email; $value_password = null; - $errors = array(); - $require_real_name = PhabricatorEnv::getEnvConfig('user.require-real-name'); $e_username = strlen($value_username) ? null : true; @@ -193,7 +249,14 @@ final class PhabricatorAuthRegisterController $e_username = null; } - if (($request->isFormPost() || !$can_edit_anything) && !$from_invite) { + $try_register = + ($request->isFormPost() || !$can_edit_anything) && + !$from_invite && + ($request->getInt('phase') != 1); + + if ($try_register) { + $errors = array(); + $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); if ($must_set_password && !$skip_captcha) { @@ -402,7 +465,8 @@ final class PhabricatorAuthRegisterController } $form = id(new AphrontFormView()) - ->setUser($request->getUser()); + ->setUser($request->getUser()) + ->addHiddenInput('phase', 2); if (!$is_default) { $form->appendChild( From 6f5dab634db26a14ba2ee000a3cee75c9d6152fb Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 17 Jan 2017 12:04:28 -0800 Subject: [PATCH 07/31] Redesign header menus and search Summary: Still lots to fix here, punting up since I'm running into a few roadblocks. TODO: [] Sort Personal/Global correctly [] Quicksand in Help Items correctly on page changes Test Plan: Verify new menus work on desktop, tablet, mobile. Test logged in menus, logged out menus. Logging out via a menu, verify each link works as expected. Help menus get build when using an app like Maniphest, Differential. Check that search works, preferences still save. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12107 Differential Revision: https://secure.phabricator.com/D17209 --- resources/celerity/map.php | 72 +++---- src/__phutil_library_map__.php | 18 +- .../PhabricatorAuthMainMenuBarExtension.php | 37 +--- .../base/PhabricatorApplication.php | 20 +- .../CelerityDefaultPostprocessor.php | 2 +- .../PhabricatorFavoritesApplication.php | 62 +++++- .../PhabricatorFavoritesConstants.php | 2 +- .../PhabricatorFavoritesMainController.php | 5 + ...PhabricatorFavoritesMenuItemController.php | 6 +- .../PhabricatorFavoritesProfileMenuEngine.php | 7 +- ...bricatorFavoritesManageProfileMenuItem.php | 72 ------- ...PhabricatorHelpDocumentationController.php | 1 - .../PhabricatorHelpMainMenuBarExtension.php | 70 ------- .../PhabricatorHomeApplication.php | 140 +++++++------ .../PhabricatorHomeQuickCreateController.php | 47 ----- .../PhabricatorPeopleMainMenuBarExtension.php | 41 ---- .../PhabricatorPhameApplication.php | 2 +- .../engine/PhabricatorProfileMenuEngine.php | 50 ++++- ...catorProfileMenuItemConfigurationQuery.php | 6 + ...habricatorSettingsMainMenuBarExtension.php | 29 --- ...habricatorEditEngineCreateQuickActions.php | 46 ----- .../quickmenu/PhabricatorQuickActions.php | 54 ----- src/view/layout/PhabricatorActionListView.php | 24 ++- src/view/layout/PhabricatorActionView.php | 42 ++++ src/view/page/PhabricatorStandardPageView.php | 9 +- .../menu/PhabricatorMainMenuSearchView.php | 10 +- .../page/menu/PhabricatorMainMenuView.php | 97 +++------ src/view/phui/PHUIButtonView.php | 10 + src/view/phui/PHUIListItemView.php | 4 +- src/view/phui/PHUIMainMenuView.php | 31 --- src/view/phui/PHUITimelineEventView.php | 12 +- .../css/application/base/main-menu-view.css | 190 +++++++++--------- .../application/base/notification-menu.css | 2 +- webroot/rsrc/css/phui/phui-action-list.css | 69 ++++--- webroot/rsrc/css/phui/phui-button.css | 6 +- webroot/rsrc/css/phui/phui-document-pro.css | 2 +- webroot/rsrc/css/phui/phui-form-view.css | 3 +- .../rsrc/css/phui/phui-two-column-view.css | 22 +- webroot/rsrc/js/phuix/PHUIXActionView.js | 15 +- 39 files changed, 527 insertions(+), 810 deletions(-) delete mode 100644 src/applications/favorites/menuitem/PhabricatorFavoritesManageProfileMenuItem.php delete mode 100644 src/applications/help/extension/PhabricatorHelpMainMenuBarExtension.php delete mode 100644 src/applications/home/controller/PhabricatorHomeQuickCreateController.php delete mode 100644 src/applications/people/extension/PhabricatorPeopleMainMenuBarExtension.php delete mode 100644 src/applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php delete mode 100644 src/applications/settings/quickmenu/PhabricatorEditEngineCreateQuickActions.php delete mode 100644 src/applications/settings/quickmenu/PhabricatorQuickActions.php delete mode 100644 src/view/phui/PHUIMainMenuView.php diff --git a/resources/celerity/map.php b/resources/celerity/map.php index ac4dd3c2a6..0102a54ed8 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,8 +9,8 @@ return array( 'names' => array( 'conpherence.pkg.css' => '0b64e988', 'conpherence.pkg.js' => '6249a1cf', - 'core.pkg.css' => '1afa1d13', - 'core.pkg.js' => '892976d4', + 'core.pkg.css' => '85f51b68', + 'core.pkg.js' => '2c684890', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '9535a7e6', 'differential.pkg.js' => 'ddfeb49b', @@ -21,7 +21,7 @@ return array( 'maniphest.pkg.js' => '5ab2753f', 'rsrc/css/aphront/aphront-bars.css' => '231ac33c', 'rsrc/css/aphront/dark-console.css' => 'f54bf286', - 'rsrc/css/aphront/dialog-view.css' => '938f52c5', + 'rsrc/css/aphront/dialog-view.css' => '5e5aa60b', 'rsrc/css/aphront/list-filter-view.css' => '5d6f0526', 'rsrc/css/aphront/multi-column.css' => '84cc6640', 'rsrc/css/aphront/notification.css' => '3f6c89c9', @@ -34,8 +34,8 @@ 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' => 'f03e17be', - 'rsrc/css/application/base/notification-menu.css' => '1e055865', + 'rsrc/css/application/base/main-menu-view.css' => '7bc94bc2', + 'rsrc/css/application/base/notification-menu.css' => '6a697e43', 'rsrc/css/application/base/phabricator-application-launch-view.css' => '95351601', 'rsrc/css/application/base/phui-theme.css' => '798c69b8', 'rsrc/css/application/base/standard-page-view.css' => '894d8a25', @@ -96,7 +96,7 @@ return array( 'rsrc/css/application/policy/policy-transaction-detail.css' => '82100a43', 'rsrc/css/application/policy/policy.css' => '957ea14c', 'rsrc/css/application/ponder/ponder-view.css' => 'fbd45f96', - 'rsrc/css/application/project/project-card-view.css' => '9418c97d', + 'rsrc/css/application/project/project-card-view.css' => 'd27c67ae', 'rsrc/css/application/project/project-view.css' => '1e6f7072', 'rsrc/css/application/releeph/releeph-core.css' => '9b3c5733', 'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5', @@ -108,7 +108,7 @@ return array( 'rsrc/css/application/tokens/tokens.css' => '3d0f239e', 'rsrc/css/application/uiexample/example.css' => '528b19de', 'rsrc/css/core/core.css' => 'd0801452', - 'rsrc/css/core/remarkup.css' => 'aebc1180', + 'rsrc/css/core/remarkup.css' => '4a2de2bb', 'rsrc/css/core/syntax.css' => '769d3498', 'rsrc/css/core/z-index.css' => '5e72c4e0', 'rsrc/css/diviner/diviner-shared.css' => 'aa3656aa', @@ -128,29 +128,29 @@ return array( 'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '9d9685d6', 'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'bff632a4', 'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => 'a8beebea', - 'rsrc/css/phui/phui-action-list.css' => 'e1d48300', + 'rsrc/css/phui/phui-action-list.css' => '5679229f', 'rsrc/css/phui/phui-action-panel.css' => '91c7b835', 'rsrc/css/phui/phui-badge.css' => '3baef8db', 'rsrc/css/phui/phui-basic-nav-view.css' => '7093573b', 'rsrc/css/phui/phui-big-info-view.css' => 'bd903741', 'rsrc/css/phui/phui-box.css' => '33b629f8', - 'rsrc/css/phui/phui-button.css' => '43f4912e', + 'rsrc/css/phui/phui-button.css' => '9718cb0c', 'rsrc/css/phui/phui-chart.css' => '6bf6f78e', 'rsrc/css/phui/phui-cms.css' => 'be43c8a8', 'rsrc/css/phui/phui-comment-form.css' => '48fbd65d', 'rsrc/css/phui/phui-comment-panel.css' => 'f50152ad', 'rsrc/css/phui/phui-crumbs-view.css' => 'f82868f2', 'rsrc/css/phui/phui-curtain-view.css' => '947bf1a4', - 'rsrc/css/phui/phui-document-pro.css' => 'c354e312', + 'rsrc/css/phui/phui-document-pro.css' => 'f56738ed', 'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf', 'rsrc/css/phui/phui-document.css' => 'c32e8dec', 'rsrc/css/phui/phui-feed-story.css' => '44a9c8e9', 'rsrc/css/phui/phui-fontkit.css' => '9cda225e', - 'rsrc/css/phui/phui-form-view.css' => '04cc4771', + 'rsrc/css/phui/phui-form-view.css' => 'adca31ce', 'rsrc/css/phui/phui-form.css' => '2342b0e5', 'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f', 'rsrc/css/phui/phui-header-view.css' => '6ec8f155', - 'rsrc/css/phui/phui-hovercard.css' => 'de1a2119', + 'rsrc/css/phui/phui-hovercard.css' => 'e904f5dc', 'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad', 'rsrc/css/phui/phui-icon.css' => '09f46dd9', 'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c', @@ -170,10 +170,10 @@ return array( 'rsrc/css/phui/phui-status.css' => 'd5263e49', 'rsrc/css/phui/phui-tag-view.css' => '84d65f26', 'rsrc/css/phui/phui-timeline-view.css' => 'bc523970', - 'rsrc/css/phui/phui-two-column-view.css' => '7babf5b9', + 'rsrc/css/phui/phui-two-column-view.css' => 'a0d3858a', 'rsrc/css/phui/workboards/phui-workboard-color.css' => 'b60ef38a', 'rsrc/css/phui/workboards/phui-workboard.css' => 'c88912ee', - 'rsrc/css/phui/workboards/phui-workcard.css' => '00979e40', + 'rsrc/css/phui/workboards/phui-workcard.css' => 'cca5fa92', 'rsrc/css/phui/workboards/phui-workpanel.css' => 'a3a63478', 'rsrc/css/sprite-login.css' => '587d92d7', 'rsrc/css/sprite-tokens.css' => '9cdfd599', @@ -538,7 +538,7 @@ return array( 'rsrc/js/phui/behavior-phui-submenu.js' => 'a6f7a73b', 'rsrc/js/phui/behavior-phui-tab-group.js' => '0a0b10e9', 'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8', - 'rsrc/js/phuix/PHUIXActionView.js' => '8cf6d262', + 'rsrc/js/phuix/PHUIXActionView.js' => '9cc178ed', 'rsrc/js/phuix/PHUIXAutocomplete.js' => '6d86ce8b', 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '82e270da', 'rsrc/js/phuix/PHUIXFormControl.js' => 'bbece68d', @@ -548,7 +548,7 @@ return array( 'almanac-css' => 'dbb9b3af', 'aphront-bars' => '231ac33c', 'aphront-dark-console-css' => 'f54bf286', - 'aphront-dialog-view-css' => '938f52c5', + 'aphront-dialog-view-css' => '5e5aa60b', 'aphront-list-filter-view-css' => '5d6f0526', 'aphront-multi-column-view-css' => '84cc6640', 'aphront-panel-view-css' => '8427b78d', @@ -778,7 +778,7 @@ return array( 'paste-css' => '1898e534', 'path-typeahead' => 'f7fc67ec', 'people-profile-css' => '2473d929', - 'phabricator-action-list-view-css' => 'e1d48300', + 'phabricator-action-list-view-css' => '5679229f', 'phabricator-application-launch-view-css' => '95351601', 'phabricator-busy' => '59a7976a', 'phabricator-chatlog-css' => 'd295b020', @@ -796,15 +796,15 @@ return array( 'phabricator-flag-css' => 'bba8f811', 'phabricator-keyboard-shortcut' => '1ae869f2', 'phabricator-keyboard-shortcut-manager' => '4a021c10', - 'phabricator-main-menu-view' => 'f03e17be', + 'phabricator-main-menu-view' => '7bc94bc2', 'phabricator-nav-view-css' => 'b29426e9', 'phabricator-notification' => 'ccf1cbf8', 'phabricator-notification-css' => '3f6c89c9', - 'phabricator-notification-menu-css' => '1e055865', + 'phabricator-notification-menu-css' => '6a697e43', 'phabricator-object-selector-css' => '85ee8ce6', 'phabricator-phtize' => 'd254d646', 'phabricator-prefab' => '8d40ae75', - 'phabricator-remarkup-css' => 'aebc1180', + 'phabricator-remarkup-css' => '4a2de2bb', 'phabricator-search-results-css' => '64ad079a', 'phabricator-shaped-request' => '7cbe244b', 'phabricator-slowvote-css' => 'a94b7230', @@ -840,7 +840,7 @@ return array( 'phui-basic-nav-view-css' => '7093573b', 'phui-big-info-view-css' => 'bd903741', 'phui-box-css' => '33b629f8', - 'phui-button-css' => '43f4912e', + 'phui-button-css' => '9718cb0c', 'phui-calendar-css' => '477acfaa', 'phui-calendar-day-css' => '572b1893', 'phui-calendar-list-css' => 'fcc9fb41', @@ -853,16 +853,16 @@ return array( 'phui-curtain-view-css' => '947bf1a4', 'phui-document-summary-view-css' => '9ca48bdf', 'phui-document-view-css' => 'c32e8dec', - 'phui-document-view-pro-css' => 'c354e312', + 'phui-document-view-pro-css' => 'f56738ed', 'phui-feed-story-css' => '44a9c8e9', 'phui-font-icon-base-css' => '870a7360', 'phui-fontkit-css' => '9cda225e', 'phui-form-css' => '2342b0e5', - 'phui-form-view-css' => '04cc4771', + 'phui-form-view-css' => 'adca31ce', 'phui-head-thing-view-css' => 'fd311e5f', 'phui-header-view-css' => '6ec8f155', 'phui-hovercard' => '1bd28176', - 'phui-hovercard-view-css' => 'de1a2119', + 'phui-hovercard-view-css' => 'e904f5dc', 'phui-icon-set-selector-css' => '1ab67aad', 'phui-icon-view-css' => '09f46dd9', 'phui-image-mask-css' => 'a8498f9c', @@ -890,13 +890,13 @@ return array( 'phui-tag-view-css' => '84d65f26', 'phui-theme-css' => '798c69b8', 'phui-timeline-view-css' => 'bc523970', - 'phui-two-column-view-css' => '7babf5b9', + 'phui-two-column-view-css' => 'a0d3858a', 'phui-workboard-color-css' => 'b60ef38a', 'phui-workboard-view-css' => 'c88912ee', - 'phui-workcard-view-css' => '00979e40', + 'phui-workcard-view-css' => 'cca5fa92', 'phui-workpanel-view-css' => 'a3a63478', 'phuix-action-list-view' => 'b5c256b8', - 'phuix-action-view' => '8cf6d262', + 'phuix-action-view' => '9cc178ed', 'phuix-autocomplete' => '6d86ce8b', 'phuix-dropdown-menu' => '82e270da', 'phuix-form-control-view' => 'bbece68d', @@ -905,7 +905,7 @@ return array( 'policy-edit-css' => '815c66f7', 'policy-transaction-detail-css' => '82100a43', 'ponder-view-css' => 'fbd45f96', - 'project-card-view-css' => '9418c97d', + 'project-card-view-css' => 'd27c67ae', 'project-view-css' => '1e6f7072', 'releeph-core' => '9b3c5733', 'releeph-preview-branch' => 'b7a6f4a5', @@ -1508,6 +1508,9 @@ return array( 'owners-path-editor', 'javelin-behavior', ), + '7bc94bc2' => array( + 'phui-theme-css', + ), '7cbe244b' => array( 'javelin-install', 'javelin-util', @@ -1603,11 +1606,6 @@ return array( 'javelin-stratcom', 'javelin-behavior', ), - '8cf6d262' => array( - 'javelin-install', - 'javelin-dom', - 'javelin-util', - ), '8d3bc1b2' => array( 'javelin-dom', 'javelin-util', @@ -1707,6 +1705,11 @@ return array( 'javelin-workflow', 'javelin-stratcom', ), + '9cc178ed' => array( + 'javelin-install', + 'javelin-dom', + 'javelin-util', + ), '9d9685d6' => array( 'phui-oi-list-view-css', ), @@ -2161,9 +2164,6 @@ return array( 'javelin-workflow', 'javelin-json', ), - 'f03e17be' => array( - 'phui-theme-css', - ), 'f12cbc9f' => array( 'phui-oi-list-view-css', ), diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 4083a5aeb8..ee6508226a 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1698,7 +1698,6 @@ phutil_register_library_map(array( 'PHUIListItemView' => 'view/phui/PHUIListItemView.php', 'PHUIListView' => 'view/phui/PHUIListView.php', 'PHUIListViewTestCase' => 'view/layout/__tests__/PHUIListViewTestCase.php', - 'PHUIMainMenuView' => 'view/phui/PHUIMainMenuView.php', 'PHUIObjectBoxView' => 'view/phui/PHUIObjectBoxView.php', 'PHUIObjectItemListExample' => 'applications/uiexample/examples/PHUIObjectItemListExample.php', 'PHUIObjectItemListView' => 'view/phui/PHUIObjectItemListView.php', @@ -2592,7 +2591,6 @@ phutil_register_library_map(array( 'PhabricatorEditEngineConfigurationTransactionQuery' => 'applications/transactions/query/PhabricatorEditEngineConfigurationTransactionQuery.php', 'PhabricatorEditEngineConfigurationViewController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php', 'PhabricatorEditEngineController' => 'applications/transactions/controller/PhabricatorEditEngineController.php', - 'PhabricatorEditEngineCreateQuickActions' => 'applications/settings/quickmenu/PhabricatorEditEngineCreateQuickActions.php', 'PhabricatorEditEngineDatasource' => 'applications/transactions/typeahead/PhabricatorEditEngineDatasource.php', 'PhabricatorEditEngineExtension' => 'applications/transactions/engineextension/PhabricatorEditEngineExtension.php', 'PhabricatorEditEngineExtensionModule' => 'applications/transactions/engineextension/PhabricatorEditEngineExtensionModule.php', @@ -2673,7 +2671,6 @@ phutil_register_library_map(array( 'PhabricatorFavoritesConstants' => 'applications/favorites/constants/PhabricatorFavoritesConstants.php', 'PhabricatorFavoritesController' => 'applications/favorites/controller/PhabricatorFavoritesController.php', 'PhabricatorFavoritesMainController' => 'applications/favorites/controller/PhabricatorFavoritesMainController.php', - 'PhabricatorFavoritesManageProfileMenuItem' => 'applications/favorites/menuitem/PhabricatorFavoritesManageProfileMenuItem.php', 'PhabricatorFavoritesMenuItemController' => 'applications/favorites/controller/PhabricatorFavoritesMenuItemController.php', 'PhabricatorFavoritesProfileMenuEngine' => 'applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php', 'PhabricatorFaxContentSource' => 'infrastructure/contentsource/PhabricatorFaxContentSource.php', @@ -2828,7 +2825,6 @@ phutil_register_library_map(array( 'PhabricatorHelpDocumentationController' => 'applications/help/controller/PhabricatorHelpDocumentationController.php', 'PhabricatorHelpEditorProtocolController' => 'applications/help/controller/PhabricatorHelpEditorProtocolController.php', 'PhabricatorHelpKeyboardShortcutController' => 'applications/help/controller/PhabricatorHelpKeyboardShortcutController.php', - 'PhabricatorHelpMainMenuBarExtension' => 'applications/help/extension/PhabricatorHelpMainMenuBarExtension.php', 'PhabricatorHeraldApplication' => 'applications/herald/application/PhabricatorHeraldApplication.php', 'PhabricatorHeraldContentSource' => 'applications/herald/contentsource/PhabricatorHeraldContentSource.php', 'PhabricatorHighSecurityRequestExceptionHandler' => 'aphront/handler/PhabricatorHighSecurityRequestExceptionHandler.php', @@ -2841,7 +2837,6 @@ phutil_register_library_map(array( 'PhabricatorHomeMenuItemController' => 'applications/home/controller/PhabricatorHomeMenuItemController.php', 'PhabricatorHomePreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorHomePreferencesSettingsPanel.php', 'PhabricatorHomeProfileMenuEngine' => 'applications/home/engine/PhabricatorHomeProfileMenuEngine.php', - 'PhabricatorHomeQuickCreateController' => 'applications/home/controller/PhabricatorHomeQuickCreateController.php', 'PhabricatorHovercardEngineExtension' => 'applications/search/engineextension/PhabricatorHovercardEngineExtension.php', 'PhabricatorHovercardEngineExtensionModule' => 'applications/search/engineextension/PhabricatorHovercardEngineExtensionModule.php', 'PhabricatorIDsSearchEngineExtension' => 'applications/search/engineextension/PhabricatorIDsSearchEngineExtension.php', @@ -3317,7 +3312,6 @@ phutil_register_library_map(array( 'PhabricatorPeopleLogQuery' => 'applications/people/query/PhabricatorPeopleLogQuery.php', 'PhabricatorPeopleLogSearchEngine' => 'applications/people/query/PhabricatorPeopleLogSearchEngine.php', 'PhabricatorPeopleLogsController' => 'applications/people/controller/PhabricatorPeopleLogsController.php', - 'PhabricatorPeopleMainMenuBarExtension' => 'applications/people/extension/PhabricatorPeopleMainMenuBarExtension.php', 'PhabricatorPeopleManageProfileMenuItem' => 'applications/people/menuitem/PhabricatorPeopleManageProfileMenuItem.php', 'PhabricatorPeopleNewController' => 'applications/people/controller/PhabricatorPeopleNewController.php', 'PhabricatorPeopleNoOwnerDatasource' => 'applications/people/typeahead/PhabricatorPeopleNoOwnerDatasource.php', @@ -3562,7 +3556,6 @@ phutil_register_library_map(array( 'PhabricatorQueryOrderItem' => 'infrastructure/query/order/PhabricatorQueryOrderItem.php', 'PhabricatorQueryOrderTestCase' => 'infrastructure/query/order/__tests__/PhabricatorQueryOrderTestCase.php', 'PhabricatorQueryOrderVector' => 'infrastructure/query/order/PhabricatorQueryOrderVector.php', - 'PhabricatorQuickActions' => 'applications/settings/quickmenu/PhabricatorQuickActions.php', 'PhabricatorRateLimitRequestExceptionHandler' => 'aphront/handler/PhabricatorRateLimitRequestExceptionHandler.php', 'PhabricatorRecaptchaConfigOptions' => 'applications/config/option/PhabricatorRecaptchaConfigOptions.php', 'PhabricatorRecipientHasBadgeEdgeType' => 'applications/badges/edge/PhabricatorRecipientHasBadgeEdgeType.php', @@ -3771,7 +3764,6 @@ phutil_register_library_map(array( 'PhabricatorSettingsListController' => 'applications/settings/controller/PhabricatorSettingsListController.php', 'PhabricatorSettingsLogsPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsLogsPanelGroup.php', 'PhabricatorSettingsMainController' => 'applications/settings/controller/PhabricatorSettingsMainController.php', - 'PhabricatorSettingsMainMenuBarExtension' => 'applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php', 'PhabricatorSettingsPanel' => 'applications/settings/panel/PhabricatorSettingsPanel.php', 'PhabricatorSettingsPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsPanelGroup.php', 'PhabricatorSettingsTimezoneController' => 'applications/settings/controller/PhabricatorSettingsTimezoneController.php', @@ -6575,7 +6567,6 @@ phutil_register_library_map(array( 'PHUIListItemView' => 'AphrontTagView', 'PHUIListView' => 'AphrontTagView', 'PHUIListViewTestCase' => 'PhabricatorTestCase', - 'PHUIMainMenuView' => 'AphrontView', 'PHUIObjectBoxView' => 'AphrontTagView', 'PHUIObjectItemListExample' => 'PhabricatorUIExample', 'PHUIObjectItemListView' => 'AphrontTagView', @@ -6679,7 +6670,7 @@ phutil_register_library_map(array( 'PhabricatorAccessLogConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorAccessibilitySetting' => 'PhabricatorSelectSetting', 'PhabricatorAccountSettingsPanel' => 'PhabricatorEditEngineSettingsPanel', - 'PhabricatorActionListView' => 'AphrontView', + 'PhabricatorActionListView' => 'AphrontTagView', 'PhabricatorActionView' => 'AphrontView', 'PhabricatorActivitySettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorAdministratorsPolicyRule' => 'PhabricatorPolicyRule', @@ -7613,7 +7604,6 @@ phutil_register_library_map(array( 'PhabricatorEditEngineConfigurationTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorEditEngineConfigurationViewController' => 'PhabricatorEditEngineController', 'PhabricatorEditEngineController' => 'PhabricatorApplicationTransactionController', - 'PhabricatorEditEngineCreateQuickActions' => 'PhabricatorQuickActions', 'PhabricatorEditEngineDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorEditEngineExtension' => 'Phobject', 'PhabricatorEditEngineExtensionModule' => 'PhabricatorConfigModule', @@ -7696,7 +7686,6 @@ phutil_register_library_map(array( 'PhabricatorFavoritesConstants' => 'PhabricatorFavoritesController', 'PhabricatorFavoritesController' => 'PhabricatorController', 'PhabricatorFavoritesMainController' => 'PhabricatorFavoritesController', - 'PhabricatorFavoritesManageProfileMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorFavoritesMenuItemController' => 'PhabricatorFavoritesController', 'PhabricatorFavoritesProfileMenuEngine' => 'PhabricatorProfileMenuEngine', 'PhabricatorFaxContentSource' => 'PhabricatorContentSource', @@ -7887,7 +7876,6 @@ phutil_register_library_map(array( 'PhabricatorHelpDocumentationController' => 'PhabricatorHelpController', 'PhabricatorHelpEditorProtocolController' => 'PhabricatorHelpController', 'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController', - 'PhabricatorHelpMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 'PhabricatorHeraldApplication' => 'PhabricatorApplication', 'PhabricatorHeraldContentSource' => 'PhabricatorContentSource', 'PhabricatorHighSecurityRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler', @@ -7900,7 +7888,6 @@ phutil_register_library_map(array( 'PhabricatorHomeMenuItemController' => 'PhabricatorHomeController', 'PhabricatorHomePreferencesSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorHomeProfileMenuEngine' => 'PhabricatorProfileMenuEngine', - 'PhabricatorHomeQuickCreateController' => 'PhabricatorHomeController', 'PhabricatorHovercardEngineExtension' => 'Phobject', 'PhabricatorHovercardEngineExtensionModule' => 'PhabricatorConfigModule', 'PhabricatorIDsSearchEngineExtension' => 'PhabricatorSearchEngineExtension', @@ -8450,7 +8437,6 @@ phutil_register_library_map(array( 'PhabricatorPeopleLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPeopleLogSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController', - 'PhabricatorPeopleMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 'PhabricatorPeopleManageProfileMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorPeopleNewController' => 'PhabricatorPeopleController', 'PhabricatorPeopleNoOwnerDatasource' => 'PhabricatorTypeaheadDatasource', @@ -8749,7 +8735,6 @@ phutil_register_library_map(array( 'Phobject', 'Iterator', ), - 'PhabricatorQuickActions' => 'Phobject', 'PhabricatorRateLimitRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler', 'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorRecipientHasBadgeEdgeType' => 'PhabricatorEdgeType', @@ -9016,7 +9001,6 @@ phutil_register_library_map(array( 'PhabricatorSettingsListController' => 'PhabricatorController', 'PhabricatorSettingsLogsPanelGroup' => 'PhabricatorSettingsPanelGroup', 'PhabricatorSettingsMainController' => 'PhabricatorController', - 'PhabricatorSettingsMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 'PhabricatorSettingsPanel' => 'Phobject', 'PhabricatorSettingsPanelGroup' => 'Phobject', 'PhabricatorSettingsTimezoneController' => 'PhabricatorController', diff --git a/src/applications/auth/extension/PhabricatorAuthMainMenuBarExtension.php b/src/applications/auth/extension/PhabricatorAuthMainMenuBarExtension.php index 47264517e0..2757bec91c 100644 --- a/src/applications/auth/extension/PhabricatorAuthMainMenuBarExtension.php +++ b/src/applications/auth/extension/PhabricatorAuthMainMenuBarExtension.php @@ -13,9 +13,7 @@ final class PhabricatorAuthMainMenuBarExtension $viewer = $this->getViewer(); if ($viewer->isLoggedIn()) { - return array( - $this->buildLogoutMenu(), - ); + return array(); } $controller = $this->getController(); @@ -30,25 +28,6 @@ final class PhabricatorAuthMainMenuBarExtension ); } - private function buildLogoutMenu() { - $controller = $this->getController(); - - $is_selected = ($controller instanceof PhabricatorLogoutController); - - $bar_item = id(new PHUIListItemView()) - ->addClass('core-menu-item') - ->setName(pht('Log Out')) - ->setIcon('fa-sign-out') - ->setWorkflow(true) - ->setHref('/logout/') - ->setSelected($is_selected) - ->setAural(pht('Log Out')); - - return id(new PHUIMainMenuView()) - ->setOrder(900) - ->setMenuBarItem($bar_item); - } - private function buildLoginMenu() { $controller = $this->getController(); @@ -58,16 +37,12 @@ final class PhabricatorAuthMainMenuBarExtension $uri->setQueryParam('next', $path); } - $bar_item = id(new PHUIListItemView()) - ->addClass('core-menu-item') - ->setName(pht('Log In')) - ->setIcon('fa-sign-in') + return id(new PHUIButtonView()) + ->setTag('a') + ->setText(pht('Log In')) ->setHref($uri) - ->setAural(pht('Log In')); - - return id(new PHUIMainMenuView()) - ->setOrder(900) - ->setMenuBarItem($bar_item); + ->setNoCSS(true) + ->addClass('phabricator-core-login-button'); } } diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php index 95045623d0..2136a3e4b0 100644 --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -172,36 +172,24 @@ abstract class PhabricatorApplication $articles = $this->getHelpDocumentationArticles($viewer); if ($articles) { - $items[] = id(new PHUIListItemView()) - ->setType(PHUIListItemView::TYPE_LABEL) - ->setName(pht('%s Documentation', $this->getName())); foreach ($articles as $article) { - $item = id(new PHUIListItemView()) + $item = id(new PhabricatorActionView()) ->setName($article['name']) - ->setIcon('fa-book') - ->setHref($article['href']) - ->setOpenInNewWindow(true); - + ->setHref($article['href']); $items[] = $item; } } $command_specs = $this->getMailCommandObjects(); if ($command_specs) { - $items[] = id(new PHUIListItemView()) - ->setType(PHUIListItemView::TYPE_LABEL) - ->setName(pht('Email Help')); foreach ($command_specs as $key => $spec) { $object = $spec['object']; $class = get_class($this); $href = '/applications/mailcommands/'.$class.'/'.$key.'/'; - - $item = id(new PHUIListItemView()) + $item = id(new PhabricatorActionView()) ->setName($spec['name']) - ->setIcon('fa-envelope-o') - ->setHref($href) - ->setOpenInNewWindow(true); + ->setHref($href); $items[] = $item; } } diff --git a/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php b/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php index be5bfc14c2..b68c23d69b 100644 --- a/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php +++ b/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php @@ -29,7 +29,7 @@ final class CelerityDefaultPostprocessor "Arial, sans-serif", // Drop Shadow - 'dropshadow' => '0 1px 6px rgba(0, 0, 0, .25)', + 'dropshadow' => '0 2px 12px rgba(0, 0, 0, .20)', 'whitetextshadow' => '0 1px 0 rgba(255, 255, 255, 1)', // Anchors diff --git a/src/applications/favorites/application/PhabricatorFavoritesApplication.php b/src/applications/favorites/application/PhabricatorFavoritesApplication.php index 3c5211fec4..6ae45319a0 100644 --- a/src/applications/favorites/application/PhabricatorFavoritesApplication.php +++ b/src/applications/favorites/application/PhabricatorFavoritesApplication.php @@ -15,7 +15,7 @@ final class PhabricatorFavoritesApplication extends PhabricatorApplication { } public function getIcon() { - return 'fa-star-o'; + return 'fa-star'; } public function getRoutes() { @@ -32,8 +32,64 @@ final class PhabricatorFavoritesApplication extends PhabricatorApplication { return false; } - public function getApplicationOrder() { - return 9; + public function buildMainMenuExtraNodes( + PhabricatorUser $viewer, + PhabricatorController $controller = null) { + + return id(new PHUIButtonView()) + ->setTag('a') + ->setHref('#') + ->setIcon('fa-star') + ->addClass('phabricator-core-user-menu') + ->setNoCSS(true) + ->setDropdown(true) + ->setDropdownMenu($this->renderFavoritesDropdown($viewer)); + } + + private function renderFavoritesDropdown(PhabricatorUser $viewer) { + + $application = __CLASS__; + $favorites = id(new PhabricatorApplicationQuery()) + ->setViewer($viewer) + ->withClasses(array($application)) + ->withInstalled(true) + ->executeOne(); + + $filter_view = id(new PhabricatorFavoritesProfileMenuEngine()) + ->setViewer($viewer) + ->setProfileObject($favorites) + ->setMenuType(PhabricatorProfileMenuEngine::MENU_COMBINED) + ->buildNavigation(); + + $menu_view = $filter_view->getMenu(); + $item_views = $menu_view->getItems(); + + $view = id(new PhabricatorActionListView()) + ->setViewer($viewer); + foreach ($item_views as $item) { + $type = null; + if (!strlen($item->getName())) { + $type = PhabricatorActionView::TYPE_DIVIDER; + } + $action = id(new PhabricatorActionView()) + ->setName($item->getName()) + ->setHref($item->getHref()) + ->setType($type); + $view->addAction($action); + } + + // Build out edit interface + if ($viewer->isLoggedIn()) { + $view->addAction( + id(new PhabricatorActionView()) + ->setType(PhabricatorActionView::TYPE_DIVIDER)); + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Edit Favorites')) + ->setHref('/favorites/')); + } + + return $view; } } diff --git a/src/applications/favorites/constants/PhabricatorFavoritesConstants.php b/src/applications/favorites/constants/PhabricatorFavoritesConstants.php index c11a435eef..2beb4fd1cc 100644 --- a/src/applications/favorites/constants/PhabricatorFavoritesConstants.php +++ b/src/applications/favorites/constants/PhabricatorFavoritesConstants.php @@ -6,6 +6,6 @@ final class PhabricatorFavoritesConstants const ITEM_TASK = 'favorites.task'; const ITEM_PROJECT = 'favorites.project'; const ITEM_REPOSITORY = 'favorites.repository'; - const ITEM_MANAGE = 'favorites.manage'; + const ITEM_DIVIDER = 'favorites.divider'; } diff --git a/src/applications/favorites/controller/PhabricatorFavoritesMainController.php b/src/applications/favorites/controller/PhabricatorFavoritesMainController.php index c083b764b6..54197a6635 100644 --- a/src/applications/favorites/controller/PhabricatorFavoritesMainController.php +++ b/src/applications/favorites/controller/PhabricatorFavoritesMainController.php @@ -10,6 +10,11 @@ final class PhabricatorFavoritesMainController public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); + if (!$viewer->getIsAdmin()) { + $uri = '/favorites/personal/item/configure/'; + return id(new AphrontRedirectResponse())->setURI($uri); + } + $menu = id(new PHUIObjectItemListView()) ->setUser($viewer); diff --git a/src/applications/favorites/controller/PhabricatorFavoritesMenuItemController.php b/src/applications/favorites/controller/PhabricatorFavoritesMenuItemController.php index a398cf6ee8..912d9efe0d 100644 --- a/src/applications/favorites/controller/PhabricatorFavoritesMenuItemController.php +++ b/src/applications/favorites/controller/PhabricatorFavoritesMenuItemController.php @@ -7,8 +7,10 @@ final class PhabricatorFavoritesMenuItemController $viewer = $this->getViewer(); $type = $request->getURIData('type'); $custom_phid = null; + $menu = PhabricatorProfileMenuEngine::MENU_GLOBAL; if ($type == 'personal') { $custom_phid = $viewer->getPHID(); + $menu = PhabricatorProfileMenuEngine::MENU_PERSONAL; } $application = 'PhabricatorFavoritesApplication'; @@ -21,7 +23,9 @@ final class PhabricatorFavoritesMenuItemController $engine = id(new PhabricatorFavoritesProfileMenuEngine()) ->setProfileObject($favorites) ->setCustomPHID($custom_phid) - ->setController($this); + ->setController($this) + ->setMenuType($menu) + ->setShowNavigation(false); return $engine->buildResponse(); } diff --git a/src/applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php b/src/applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php index a12922a6e8..ff994e4793 100644 --- a/src/applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php +++ b/src/applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php @@ -21,6 +21,7 @@ final class PhabricatorFavoritesProfileMenuEngine protected function getBuiltinProfileItems($object) { $items = array(); $custom_phid = $this->getCustomPHID(); + $viewer = $this->getViewer(); // Built-in Global Defaults if (!$custom_phid) { @@ -58,12 +59,6 @@ final class PhabricatorFavoritesProfileMenuEngine ->setMenuItemProperties($create_repository); } - // Single Manage Item, switches URI based on admin/user - $items[] = $this->newItem() - ->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_MANAGE) - ->setMenuItemKey( - PhabricatorFavoritesManageProfileMenuItem::MENUITEMKEY); - return $items; } diff --git a/src/applications/favorites/menuitem/PhabricatorFavoritesManageProfileMenuItem.php b/src/applications/favorites/menuitem/PhabricatorFavoritesManageProfileMenuItem.php deleted file mode 100644 index 36847061bf..0000000000 --- a/src/applications/favorites/menuitem/PhabricatorFavoritesManageProfileMenuItem.php +++ /dev/null @@ -1,72 +0,0 @@ -getMenuItemProperty('name'); - - if (strlen($name)) { - return $name; - } - - return $this->getDefaultName(); - } - - public function buildEditEngineFields( - PhabricatorProfileMenuItemConfiguration $config) { - return array( - id(new PhabricatorTextEditField()) - ->setKey('name') - ->setLabel(pht('Name')) - ->setPlaceholder($this->getDefaultName()) - ->setValue($config->getMenuItemProperty('name')), - ); - } - - protected function newNavigationMenuItems( - PhabricatorProfileMenuItemConfiguration $config) { - $viewer = $this->getViewer(); - - if ($viewer->isLoggedIn()) { - $admin = $viewer->getIsAdmin(); - $name = $this->getDisplayName($config); - $icon = 'fa-pencil'; - $href = '/favorites/personal/item/configure/'; - if ($admin) { - $href = '/favorites/'; - } - - $item = $this->newItem() - ->setHref($href) - ->setName($name) - ->setIcon($icon); - } - - return array( - $item, - ); - } - -} diff --git a/src/applications/help/controller/PhabricatorHelpDocumentationController.php b/src/applications/help/controller/PhabricatorHelpDocumentationController.php index 4983520bab..82a6de6ec5 100644 --- a/src/applications/help/controller/PhabricatorHelpDocumentationController.php +++ b/src/applications/help/controller/PhabricatorHelpDocumentationController.php @@ -31,7 +31,6 @@ final class PhabricatorHelpDocumentationController $list->addItem( id(new PHUIObjectItemView()) ->setHeader($item->getName()) - ->setWorkflow($item->getWorkflow()) ->setHref($item->getHref())); } diff --git a/src/applications/help/extension/PhabricatorHelpMainMenuBarExtension.php b/src/applications/help/extension/PhabricatorHelpMainMenuBarExtension.php deleted file mode 100644 index 3d2969c035..0000000000 --- a/src/applications/help/extension/PhabricatorHelpMainMenuBarExtension.php +++ /dev/null @@ -1,70 +0,0 @@ -getApplication(); - if (!$application) { - return array(); - } - - $viewer = $this->getViewer(); - $help_links = $application->getHelpMenuItems($viewer); - if (!$help_links) { - return array(); - } - - $help_id = celerity_generate_unique_node_id(); - - Javelin::initBehavior( - 'aphlict-dropdown', - array( - 'bubbleID' => $help_id, - 'dropdownID' => 'phabricator-help-menu', - 'local' => true, - 'desktop' => true, - 'right' => true, - )); - - $help_name = pht('%s Help', $application->getName()); - - $help_item = id(new PHUIListItemView()) - ->setIcon('fa-book') - ->addClass('core-menu-item') - ->setID($help_id) - ->setName($help_name) - ->setHref('/help/documentation/'.get_class($application).'/') - ->setAural($help_name); - - $view = new PHUIListView(); - foreach ($help_links as $help_link) { - $view->addMenuItem($help_link); - } - - $dropdown_menu = phutil_tag( - 'div', - array( - 'id' => 'phabricator-help-menu', - 'class' => 'phabricator-main-menu-dropdown phui-list-sidenav', - 'style' => 'display: none', - ), - $view); - - $help_menu = id(new PHUIMainMenuView()) - ->setOrder(200) - ->setMenuBarItem($help_item) - ->appendChild($dropdown_menu); - - return array( - $help_menu, - ); - } - -} diff --git a/src/applications/home/application/PhabricatorHomeApplication.php b/src/applications/home/application/PhabricatorHomeApplication.php index 8d1b97a797..9364879e18 100644 --- a/src/applications/home/application/PhabricatorHomeApplication.php +++ b/src/applications/home/application/PhabricatorHomeApplication.php @@ -2,7 +2,8 @@ final class PhabricatorHomeApplication extends PhabricatorApplication { - private $quickItems; + private $application; + const DASHBOARD_DEFAULT = 'dashboard:default'; public function getBaseURI() { @@ -26,7 +27,6 @@ final class PhabricatorHomeApplication extends PhabricatorApplication { '/' => 'PhabricatorHomeMainController', '/(?Phome)/' => 'PhabricatorHomeMainController', '/home/' => array( - 'create/' => 'PhabricatorHomeQuickCreateController', 'menu/' => array( '' => 'PhabricatorHomeMenuController', '(?Pglobal|personal)/item/' => $this->getProfileMenuRouting( @@ -44,73 +44,87 @@ final class PhabricatorHomeApplication extends PhabricatorApplication { return 9; } - public function buildMainMenuItems( - PhabricatorUser $user, - PhabricatorController $controller = null) { - - $quick_items = $this->getQuickActionItems($user); - if (!$quick_items) { - return array(); - } - - $items = array(); - $create_id = celerity_generate_unique_node_id(); - - Javelin::initBehavior( - 'aphlict-dropdown', - array( - 'bubbleID' => $create_id, - 'dropdownID' => 'phabricator-quick-create-menu', - 'local' => true, - 'desktop' => true, - 'right' => true, - )); - - $item = id(new PHUIListItemView()) - ->setName(pht('Quick Actions')) - ->setIcon('fa-plus') - ->addClass('core-menu-item') - ->setHref('/home/create/') - ->addSigil('quick-create-menu') - ->setID($create_id) - ->setAural(pht('Quick Actions')) - ->setOrder(300); - $items[] = $item; - - return $items; - } - public function buildMainMenuExtraNodes( PhabricatorUser $viewer, PhabricatorController $controller = null) { - $items = $this->getQuickActionItems($viewer); - - $view = null; - if ($items) { - $view = new PHUIListView(); - foreach ($items as $item) { - $view->addMenuItem($item); - } - - return phutil_tag( - 'div', - array( - 'id' => 'phabricator-quick-create-menu', - 'class' => 'phabricator-main-menu-dropdown phui-list-sidenav', - 'style' => 'display: none', - ), - $view); + if (!$viewer->isLoggedIn()) { + return; } + + $image = $viewer->getProfileImageURI(); + if ($controller) { + $this->application = $controller->getCurrentApplication(); + } + + $profile_image = id(new PHUIIconView()) + ->setImage($image) + ->setHeadSize(PHUIIconView::HEAD_SMALL); + + return id(new PHUIButtonView()) + ->setTag('a') + ->setHref('/p/'.$viewer->getUsername().'/') + ->setIcon($profile_image) + ->addClass('phabricator-core-user-menu') + ->setNoCSS(true) + ->setDropdown(true) + ->setDropdownMenu($this->renderUserDropdown($viewer)); + } + + private function renderUserDropdown(PhabricatorUser $viewer) { + + $view = id(new PhabricatorActionListView()) + ->setViewer($viewer); + + // User Menu + $view->addAction( + id(new PhabricatorActionView()) + ->setName($viewer->getRealName()) + ->setLabel(true)); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Profile')) + ->setHref('/p/'.$viewer->getUsername().'/')); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Settings')) + ->setHref('/settings/user/'.$viewer->getUsername().'/')); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Manage')) + ->setHref('/people/manage/'.$viewer->getID().'/')); + + // Help Menus + if ($this->application) { + $application = $this->application; + $help_links = $application->getHelpMenuItems($viewer); + if ($help_links) { + $view->addAction( + id(new PhabricatorActionView()) + ->setType(PhabricatorActionView::TYPE_DIVIDER)); + + foreach ($help_links as $link) { + $link->setOpenInNewWindow(true); + $view->addAction($link); + } + } + } + + // Logout Menu + $view->addAction( + id(new PhabricatorActionView()) + ->setType(PhabricatorActionView::TYPE_DIVIDER)); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Log Out %s', $viewer->getUsername())) + ->setHref('/logout/') + ->setWorkflow(true)); + return $view; } - private function getQuickActionItems(PhabricatorUser $viewer) { - if ($this->quickItems === null) { - $items = PhabricatorQuickActions::loadMenuItemsForUser($viewer); - $this->quickItems = $items; - } - return $this->quickItems; - } - } diff --git a/src/applications/home/controller/PhabricatorHomeQuickCreateController.php b/src/applications/home/controller/PhabricatorHomeQuickCreateController.php deleted file mode 100644 index 0100c40366..0000000000 --- a/src/applications/home/controller/PhabricatorHomeQuickCreateController.php +++ /dev/null @@ -1,47 +0,0 @@ -getViewer(); - - $items = PhabricatorQuickActions::loadMenuItemsForUser($viewer); - - $list = id(new PHUIObjectItemListView()) - ->setUser($viewer); - - foreach ($items as $item) { - $list->addItem( - id(new PHUIObjectItemView()) - ->setHeader($item->getName()) - ->setWorkflow($item->getWorkflow()) - ->setHref($item->getHref())); - } - - $title = pht('Quick Create'); - - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb(pht('Quick Create')); - $crumbs->setBorder(true); - - $box = id(new PHUIObjectBoxView()) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setObjectList($list); - - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon('fa-plus-square'); - - $view = id(new PHUITwoColumnView()) - ->setHeader($header) - ->setFooter($box); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - - } - -} diff --git a/src/applications/people/extension/PhabricatorPeopleMainMenuBarExtension.php b/src/applications/people/extension/PhabricatorPeopleMainMenuBarExtension.php deleted file mode 100644 index 5028280ac4..0000000000 --- a/src/applications/people/extension/PhabricatorPeopleMainMenuBarExtension.php +++ /dev/null @@ -1,41 +0,0 @@ -getViewer(); - $image = $viewer->getProfileImageURI(); - - $bar_item = id(new PHUIListItemView()) - ->setName($viewer->getUsername()) - ->setHref('/p/'.$viewer->getUsername().'/') - ->addClass('core-menu-item') - ->setAural(pht('Profile')); - - $classes = array( - 'phabricator-core-menu-icon', - 'phabricator-core-menu-profile-image', - ); - - $bar_item->appendChild( - phutil_tag( - 'span', - array( - 'class' => implode(' ', $classes), - 'style' => 'background-image: url('.$image.')', - ), - '')); - - $profile_menu = id(new PHUIMainMenuView()) - ->setOrder(100) - ->setMenuBarItem($bar_item); - - return array( - $profile_menu, - ); - } - -} diff --git a/src/applications/phame/application/PhabricatorPhameApplication.php b/src/applications/phame/application/PhabricatorPhameApplication.php index 8b4d991591..677872ba1e 100644 --- a/src/applications/phame/application/PhabricatorPhameApplication.php +++ b/src/applications/phame/application/PhabricatorPhameApplication.php @@ -11,7 +11,7 @@ final class PhabricatorPhameApplication extends PhabricatorApplication { } public function getIcon() { - return 'fa-star'; + return 'fa-feed'; } public function getShortDescription() { diff --git a/src/applications/search/engine/PhabricatorProfileMenuEngine.php b/src/applications/search/engine/PhabricatorProfileMenuEngine.php index 34b02413a4..b3c341178b 100644 --- a/src/applications/search/engine/PhabricatorProfileMenuEngine.php +++ b/src/applications/search/engine/PhabricatorProfileMenuEngine.php @@ -6,9 +6,15 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { private $profileObject; private $customPHID; private $items; + private $menuType; private $defaultItem; private $controller; private $navigation; + private $showNavigation = true; + + const MENU_GLOBAL = 'global'; + const MENU_PERSONAL = 'personal'; + const MENU_COMBINED = 'menu'; public function setViewer(PhabricatorUser $viewer) { $this->viewer = $viewer; @@ -57,6 +63,24 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { return $this->defaultItem; } + public function setMenuType($type) { + $this->menuType = $type; + return $this; + } + + private function getMenuType() { + return $this->menuType; + } + + public function setShowNavigation($show) { + $this->showNavigation = $show; + return $this; + } + + public function getShowNavigation() { + return $this->showNavigation; + } + abstract protected function getItemURI($path); abstract protected function isMenuEngineConfigurable(); @@ -130,6 +154,14 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { $navigation->selectFilter('item.configure'); $crumbs = $controller->buildApplicationCrumbsForEditEngine(); + switch ($this->getMenuType()) { + case 'personal': + $crumbs->addTextCrumb(pht('Personal')); + break; + case 'global': + $crumbs->addTextCrumb(pht('Global')); + break; + } switch ($item_action) { case 'view': @@ -177,11 +209,15 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { $crumbs->setBorder(true); - return $controller->newPage() + $page = $controller->newPage() ->setTitle(pht('Configure Menu')) - ->setNavigation($navigation) ->setCrumbs($crumbs) ->appendChild($content); + + if ($this->getShowNavigation()) { + $page->setNavigation($navigation); + } + return $page; } public function buildNavigation() { @@ -258,17 +294,20 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { $object = $this->getProfileObject(); $items = $this->loadBuiltinProfileItems(); + $menu = $this->getMenuType(); if ($this->getCustomPHID()) { $stored_items = id(new PhabricatorProfileMenuItemConfigurationQuery()) ->setViewer($viewer) ->withProfilePHIDs(array($object->getPHID())) ->withCustomPHIDs(array($this->getCustomPHID())) + ->setMenuType($menu) ->execute(); } else { $stored_items = id(new PhabricatorProfileMenuItemConfigurationQuery()) ->setViewer($viewer) ->withProfilePHIDs(array($object->getPHID())) + ->setMenuType($menu) ->execute(); } @@ -501,7 +540,8 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { )); $list = id(new PHUIObjectItemListView()) - ->setID($list_id); + ->setID($list_id) + ->setNoDataString(pht('This menu currently has no items.')); foreach ($items as $item) { $id = $item->getID(); @@ -638,11 +678,11 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { ->setName($doc_name)); $header = id(new PHUIHeaderView()) - ->setHeader(pht('Profile Menu Items')) + ->setHeader(pht('Menu Items')) ->setHeaderIcon('fa-list'); $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Navigation')) + ->setHeaderText(pht('Current Menu Items')) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setObjectList($list); diff --git a/src/applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php b/src/applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php index eb09044d63..2256be446f 100644 --- a/src/applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php +++ b/src/applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php @@ -7,6 +7,7 @@ final class PhabricatorProfileMenuItemConfigurationQuery private $phids; private $profilePHIDs; private $customPHIDs; + private $menuType; public function withIDs(array $ids) { $this->ids = $ids; @@ -28,6 +29,11 @@ final class PhabricatorProfileMenuItemConfigurationQuery return $this; } + public function setMenuType($type) { + $this->menuType = $type; + return $this; + } + public function newResultObject() { return new PhabricatorProfileMenuItemConfiguration(); } diff --git a/src/applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php b/src/applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php deleted file mode 100644 index 21534c4237..0000000000 --- a/src/applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php +++ /dev/null @@ -1,29 +0,0 @@ -getController(); - $is_selected = ($controller instanceof PhabricatorSettingsMainController); - - $bar_item = id(new PHUIListItemView()) - ->setName(pht('Settings')) - ->setIcon('fa-wrench') - ->addClass('core-menu-item') - ->setSelected($is_selected) - ->setHref('/settings/') - ->setAural(pht('Settings')); - - $settings_menu = id(new PHUIMainMenuView()) - ->setMenuBarItem($bar_item) - ->setOrder(400); - - return array( - $settings_menu, - ); - } - -} diff --git a/src/applications/settings/quickmenu/PhabricatorEditEngineCreateQuickActions.php b/src/applications/settings/quickmenu/PhabricatorEditEngineCreateQuickActions.php deleted file mode 100644 index e4a8c520e5..0000000000 --- a/src/applications/settings/quickmenu/PhabricatorEditEngineCreateQuickActions.php +++ /dev/null @@ -1,46 +0,0 @@ -getViewer(); - - $engines = PhabricatorEditEngine::getAllEditEngines(); - - foreach ($engines as $key => $engine) { - if (!$engine->hasQuickCreateActions()) { - unset($engines[$key]); - } - } - - if (!$engines) { - return array(); - } - - $engine_keys = array_keys($engines); - - $configs = id(new PhabricatorEditEngineConfigurationQuery()) - ->setViewer($viewer) - ->withEngineKeys($engine_keys) - ->withIsDefault(true) - ->withIsDisabled(false) - ->execute(); - $configs = msort($configs, 'getCreateSortKey'); - $configs = mgroup($configs, 'getEngineKey'); - - $items = array(); - foreach ($engines as $key => $engine) { - $engine_configs = idx($configs, $key, array()); - $engine_items = $engine->newQuickCreateActions($engine_configs); - foreach ($engine_items as $engine_item) { - $items[] = $engine_item; - } - } - - return $items; - } - -} diff --git a/src/applications/settings/quickmenu/PhabricatorQuickActions.php b/src/applications/settings/quickmenu/PhabricatorQuickActions.php deleted file mode 100644 index 8a7711b809..0000000000 --- a/src/applications/settings/quickmenu/PhabricatorQuickActions.php +++ /dev/null @@ -1,54 +0,0 @@ -viewer = $viewer; - return $this; - } - - public function getViewer() { - return $this->viewer; - } - - public function isEnabled() { - return true; - } - - abstract public function getQuickMenuItems(); - - final public function getQuickActionsKey() { - return $this->getPhobjectClassConstant('QUICKACTIONSKEY'); - } - - public static function getAllQuickActions() { - return id(new PhutilClassMapQuery()) - ->setAncestorClass(__CLASS__) - ->setUniqueMethod('getQuickActionsKey') - ->execute(); - } - - public static function loadMenuItemsForUser(PhabricatorUser $viewer) { - $actions = self::getAllQuickActions(); - - foreach ($actions as $key => $action) { - $action->setViewer($viewer); - if (!$action->isEnabled()) { - unset($actions[$key]); - continue; - } - } - - $items = array(); - foreach ($actions as $key => $action) { - foreach ($action->getQuickMenuItems() as $item) { - $items[] = $item; - } - } - - return $items; - } - -} diff --git a/src/view/layout/PhabricatorActionListView.php b/src/view/layout/PhabricatorActionListView.php index fd18e7f429..5ac28f81de 100644 --- a/src/view/layout/PhabricatorActionListView.php +++ b/src/view/layout/PhabricatorActionListView.php @@ -1,6 +1,6 @@ id; } - public function render() { + protected function getTagName() { + return 'ul'; + } + + protected function getTagAttributes() { + $classes = array(); + $classes[] = 'phabricator-action-list-view'; + return array( + 'class' => implode(' ', $classes), + ); + } + + protected function getTagContent() { $viewer = $this->getViewer(); $event = new PhabricatorEvent( @@ -55,13 +67,7 @@ final class PhabricatorActionListView extends AphrontView { } } - return phutil_tag( - 'ul', - array( - 'class' => 'phabricator-action-list-view', - 'id' => $this->id, - ), - $items); + return $items; } public function getDropdownMenuMetadata() { diff --git a/src/view/layout/PhabricatorActionView.php b/src/view/layout/PhabricatorActionView.php index e7e145bee6..755ed892f0 100644 --- a/src/view/layout/PhabricatorActionView.php +++ b/src/view/layout/PhabricatorActionView.php @@ -18,6 +18,13 @@ final class PhabricatorActionView extends AphrontView { private $hidden; private $depth; private $id; + private $order; + private $color; + private $type; + + const TYPE_DIVIDER = 'type-divider'; + const TYPE_LABEL = 'label'; + const RED = 'action-item-red'; public function setSelected($selected) { $this->selected = $selected; @@ -51,6 +58,11 @@ final class PhabricatorActionView extends AphrontView { return $this; } + public function setColor($color) { + $this->color = $color; + return $this; + } + public function addSigil($sigil) { $this->sigils[] = $sigil; return $this; @@ -114,6 +126,24 @@ final class PhabricatorActionView extends AphrontView { return $this->id; } + public function setOrder($order) { + $this->order = $order; + return $this; + } + + public function getOrder() { + return $this->order; + } + + public function setType($type) { + $this->type = $type; + return $this; + } + + public function getType() { + return $this->type; + } + public function setSubmenu(array $submenu) { $this->submenu = $submenu; @@ -280,6 +310,18 @@ final class PhabricatorActionView extends AphrontView { $classes[] = 'phabricator-action-view-href'; } + if ($this->icon) { + $classes[] = 'action-has-icon'; + } + + if ($this->color) { + $classes[] = $this->color; + } + + if ($this->type) { + $classes[] = 'phabricator-action-view-'.$this->type; + } + $style = array(); if ($this->hidden) { diff --git a/src/view/page/PhabricatorStandardPageView.php b/src/view/page/PhabricatorStandardPageView.php index bd2b448be5..96e43e81fe 100644 --- a/src/view/page/PhabricatorStandardPageView.php +++ b/src/view/page/PhabricatorStandardPageView.php @@ -769,7 +769,7 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView $rendered_dropdowns = array(); $applications = array( - 'PhabricatorHelpApplication', + 'PhabricatorHomeApplication', ); foreach ($applications as $application_class) { if (!PhabricatorApplication::isClassInstalledForViewer( @@ -778,10 +778,9 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView continue; } $application = PhabricatorApplication::getByClass($application_class); - $rendered_dropdowns[$application_class] = - $application->buildMainMenuExtraNodes( - $viewer, - $controller); + $menu = $application->buildMainMenuExtraNodes($viewer, $controller); + // TODO: Doesn't work with Quicksand active. + $rendered_dropdowns[$application_class] = hsprintf('%s', $menu); } $hisec_warning_config = $this->getHighSecurityWarningConfig(); diff --git a/src/view/page/menu/PhabricatorMainMenuSearchView.php b/src/view/page/menu/PhabricatorMainMenuSearchView.php index aa1855ce17..d21d23d0fd 100644 --- a/src/view/page/menu/PhabricatorMainMenuSearchView.php +++ b/src/view/page/menu/PhabricatorMainMenuSearchView.php @@ -99,8 +99,10 @@ final class PhabricatorMainMenuSearchView extends AphrontView { 'id' => $button_id, 'class' => 'phui-icon-view phui-font-fa fa-search', ), - $search_text), - $selector, + array( + $selector, + $search_text, + )), $primary_input, $target, ))); @@ -118,7 +120,7 @@ final class PhabricatorMainMenuSearchView extends AphrontView { $items[] = array( 'icon' => 'fa-globe', - 'name' => pht('Search All Documents'), + 'name' => pht('All Documents'), 'value' => 'all', ); @@ -134,7 +136,7 @@ final class PhabricatorMainMenuSearchView extends AphrontView { $items[] = array( 'icon' => $application_icon, - 'name' => pht('Search Current Application'), + 'name' => pht('Current Application'), 'value' => PhabricatorSearchController::SCOPE_CURRENT_APPLICATION, ); diff --git a/src/view/page/menu/PhabricatorMainMenuView.php b/src/view/page/menu/PhabricatorMainMenuView.php index a28e38db06..75071a9ee5 100644 --- a/src/view/page/menu/PhabricatorMainMenuView.php +++ b/src/view/page/menu/PhabricatorMainMenuView.php @@ -52,10 +52,10 @@ final class PhabricatorMainMenuView extends AphrontView { $alerts[] = $menu; } $menu_bar = array_merge($menu_bar, $dropdowns); - $app_button = $this->renderApplicationMenuButton($header_id); + $app_button = $this->renderApplicationMenuButton(); $search_button = $this->renderSearchMenuButton($header_id); } else { - $app_button = $this->renderApplicationMenuButton($header_id); + $app_button = $this->renderApplicationMenuButton(); if (PhabricatorEnv::getEnvConfig('policy.allow-public')) { $search_button = $this->renderSearchMenuButton($header_id); } @@ -82,27 +82,17 @@ final class PhabricatorMainMenuView extends AphrontView { phutil_implode_html(' ', $aural)); } + // Build out Header Menus $applications = PhabricatorApplication::getAllInstalledApplications(); $menus = array(); $controller = $this->getController(); foreach ($applications as $application) { - $app_actions = $application->buildMainMenuItems( - $viewer, - $controller); $app_extra = $application->buildMainMenuExtraNodes( $viewer, $controller); - - foreach ($app_actions as $action) { - $menus[] = id(new PHUIMainMenuView()) - ->setMenuBarItem($action) - ->setOrder($action->getOrder()); - } - if ($app_extra !== null) { - $menus[] = id(new PHUIMainMenuView()) - ->appendChild($app_extra); + $menus[] = $app_extra; } } @@ -126,26 +116,17 @@ final class PhabricatorMainMenuView extends AphrontView { } } + // Builds out "login" button foreach ($extensions as $extension) { foreach ($extension->buildMainMenus() as $menu) { $menus[] = $menu; } } - $menus = msort($menus, 'getOrder'); - $bar_items = array(); foreach ($menus as $menu) { $menu_bar[] = $menu; - - $item = $menu->getMenuBarItem(); - if ($item === null) { - continue; - } - - $bar_items[] = $item; } - $application_menu = $this->renderApplicationMenu($bar_items); $classes = array(); $classes[] = 'phabricator-main-menu'; $classes[] = 'phabricator-main-menu-background'; @@ -162,7 +143,6 @@ final class PhabricatorMainMenuView extends AphrontView { $this->renderPhabricatorLogo(), $alerts, $aural, - $application_menu, $search_menu, $menu_bar, )); @@ -218,53 +198,37 @@ final class PhabricatorMainMenuView extends AphrontView { return $result; } - public function renderApplicationMenuButton($header_id) { - $button_id = celerity_generate_unique_node_id(); - return javelin_tag( - 'a', - array( - 'class' => 'phabricator-main-menu-expand-button '. - 'phabricator-expand-search-menu', - 'sigil' => 'jx-toggle-class', - 'meta' => array( - 'map' => array( - $header_id => 'phabricator-application-menu-expanded', - $button_id => 'menu-icon-selected', - ), - ), - ), - phutil_tag( - 'span', - array( - 'class' => 'phabricator-menu-button-icon phui-icon-view '. - 'phui-font-fa fa-bars', - 'id' => $button_id, - ), - '')); + public function renderApplicationMenuButton() { + $dropdown = $this->renderApplicationMenu(); + if (!$dropdown) { + return null; + } + + return id(new PHUIButtonView()) + ->setTag('a') + ->setHref('#') + ->setIcon('fa-bars') + ->addClass('phabricator-core-user-menu') + ->addClass('phabricator-core-user-mobile-menu') + ->setNoCSS(true) + ->setDropdownMenu($dropdown); } - private function renderApplicationMenu(array $bar_items) { + private function renderApplicationMenu() { $viewer = $this->getViewer(); - $view = $this->getApplicationMenu(); - - if (!$view) { - $view = new PHUIListView(); - } - - $view->addClass('phabricator-dark-menu'); - $view->addClass('phabricator-application-menu'); - - if ($bar_items) { - $view->addMenuItem( - id(new PHUIListItemView()) - ->setType(PHUIListItemView::TYPE_LABEL) - ->setName(pht('Actions'))); - foreach ($bar_items as $bar_item) { - $view->addMenuItem($bar_item); + if ($view) { + $items = $view->getItems(); + $view = id(new PhabricatorActionListView()) + ->setViewer($viewer); + foreach ($items as $item) { + $view->addAction( + id(new PhabricatorActionView()) + ->setName($item->getName()) + ->setHref($item->getHref()) + ->setType($item->getType())); } } - return $view; } @@ -296,7 +260,6 @@ final class PhabricatorMainMenuView extends AphrontView { private function renderPhabricatorSearchMenu() { $view = new PHUIListView(); - $view->addClass('phabricator-dark-menu'); $view->addClass('phabricator-search-menu'); $search = $this->renderSearch(); diff --git a/src/view/phui/PHUIButtonView.php b/src/view/phui/PHUIButtonView.php index bda7723ef1..ffe83500d3 100644 --- a/src/view/phui/PHUIButtonView.php +++ b/src/view/phui/PHUIButtonView.php @@ -27,6 +27,7 @@ final class PHUIButtonView extends AphrontTagView { private $disabled; private $name; private $tooltip; + private $noCSS; public function setName($name) { $this->name = $name; @@ -87,6 +88,11 @@ final class PHUIButtonView extends AphrontTagView { return $this; } + public function setNoCSS($no_css) { + $this->noCSS = $no_css; + return $this; + } + public function setIcon($icon, $first = true) { if (!($icon instanceof PHUIIconView)) { $icon = id(new PHUIIconView()) @@ -164,6 +170,10 @@ final class PHUIButtonView extends AphrontTagView { ); } + if ($this->noCSS) { + $classes = array(); + } + return array( 'class' => $classes, 'href' => $this->href, diff --git a/src/view/phui/PHUIListItemView.php b/src/view/phui/PHUIListItemView.php index 3a4909a1ee..95e4947162 100644 --- a/src/view/phui/PHUIListItemView.php +++ b/src/view/phui/PHUIListItemView.php @@ -202,7 +202,7 @@ final class PHUIListItemView extends AphrontTagView { } return array( - 'class' => $classes, + 'class' => implode(' ', $classes), ); } @@ -249,7 +249,7 @@ final class PHUIListItemView extends AphrontTagView { $name = phutil_tag( 'span', array( - 'class' => implode(' ', $classes), + 'class' => $classes, ), array( $this->name, diff --git a/src/view/phui/PHUIMainMenuView.php b/src/view/phui/PHUIMainMenuView.php deleted file mode 100644 index 7d5910dd7b..0000000000 --- a/src/view/phui/PHUIMainMenuView.php +++ /dev/null @@ -1,31 +0,0 @@ -menuItem = $menu_item; - return $this; - } - - public function getMenuBarItem() { - return $this->menuItem; - } - - public function setOrder($order) { - $this->order = $order; - return $this; - } - - public function getOrder() { - return $this->order; - } - - public function render() { - return $this->renderChildren(); - } - -} diff --git a/src/view/phui/PHUITimelineEventView.php b/src/view/phui/PHUITimelineEventView.php index a5834befd3..41113a1f14 100644 --- a/src/view/phui/PHUITimelineEventView.php +++ b/src/view/phui/PHUITimelineEventView.php @@ -606,8 +606,8 @@ final class PHUITimelineEventView extends AphrontView { $items[] = id(new PhabricatorActionView()) ->setIcon('fa-quote-left') + ->setName(pht('Quote Comment')) ->setHref('#') - ->setName(pht('Quote')) ->addSigil('transaction-quote') ->setMetadata( array( @@ -619,9 +619,9 @@ final class PHUITimelineEventView extends AphrontView { if ($this->getIsNormalComment()) { $items[] = id(new PhabricatorActionView()) - ->setIcon('fa-cutlery') + ->setIcon('fa-code') ->setHref('/transactions/raw/'.$xaction_phid.'/') - ->setName(pht('View Raw')) + ->setName(pht('View Remarkup')) ->addSigil('transaction-raw') ->setMetadata( array( @@ -648,9 +648,13 @@ final class PHUITimelineEventView extends AphrontView { if ($this->getIsRemovable()) { $items[] = id(new PhabricatorActionView()) - ->setIcon('fa-times') + ->setType(PhabricatorActionView::TYPE_DIVIDER); + + $items[] = id(new PhabricatorActionView()) + ->setIcon('fa-trash-o') ->setHref('/transactions/remove/'.$xaction_phid.'/') ->setName(pht('Remove Comment')) + ->setColor(PhabricatorActionView::RED) ->addSigil('transaction-remove') ->setMetadata( array( diff --git a/webroot/rsrc/css/application/base/main-menu-view.css b/webroot/rsrc/css/application/base/main-menu-view.css index 0e26dc47a4..2427ba4247 100644 --- a/webroot/rsrc/css/application/base/main-menu-view.css +++ b/webroot/rsrc/css/application/base/main-menu-view.css @@ -63,7 +63,7 @@ } .device-phone .phabricator-wordmark { - max-width: 112px; /* iPhone 5 limitation */ + display: none; } .phabricator-wordmark { @@ -119,7 +119,7 @@ */ .device-desktop .phabricator-main-menu-search { - width: 220px; + width: 298px; } .device .phabricator-main-menu-search { @@ -130,7 +130,7 @@ padding: 8px 0; position: relative; height: 24px; - margin: 0 8px; + margin: 0 8px 0 0; } .phabricator-main-menu-search-target { @@ -150,6 +150,7 @@ .device .phabricator-main-menu-search-container { padding: 4px 0; + margin: 0 4px; } .phabricator-main-menu .phabricator-main-menu-search input { @@ -169,9 +170,9 @@ border-style: solid; background-color: #fff; height: 28px; - padding: 3px 30px 3px 6px; + padding: 3px 28px 3px 52px; float: left; - width: 205px; + width: 280px; } .device .phabricator-main-menu-search input { @@ -196,7 +197,7 @@ .phabricator-main-menu-search button { color: {$bluetext}; position: absolute; - background: {$greybackground}; + background: transparent; border: none; outline: none; box-shadow: none; @@ -204,7 +205,7 @@ min-width: 0; height: 24px; width: 28px; - top: 10px; + top: 9px; right: -6px; margin: 0 8px 0 0; padding: 0; @@ -214,20 +215,22 @@ .phabricator-main-menu-search button.phabricator-main-menu-search-dropdown { position: absolute; right: auto; - left: -45px; - width: 40px; - background: transparent; + left: 12px; + width: 46px; + background: {$greybackground}; + z-index: 1; } .device-desktop .phabricator-main-menu-search button.phabricator-main-menu-search-dropdown { - height: 28px; - top: 8px; + height: 24px; + top: 10px; + border-radius: 3px; } .device-desktop .phabricator-main-menu-search button.phabricator-main-menu-search-dropdown:hover .phui-icon-view { - color: #fff; + color: {$sky}; } .device .phabricator-main-menu-search @@ -236,34 +239,24 @@ background: {$greybackground}; } -button.phabricator-main-menu-search-dropdown .caret:before { +button.phabricator-main-menu-search-dropdown .caret:before, +a.phabricator-core-user-menu .caret:before { content: "\f107"; font-family: FontAwesome; - color: {$hoverwhite}; } .phabricator-main-menu-search button.phabricator-main-menu-search-dropdown .phui-icon-view { - color: {$hoverwhite}; + color: {$bluetext}; font-size: 15px; - top: 6px; + top: 4px; left: 8px; } -.device - .phabricator-main-menu-search button.phabricator-main-menu-search-dropdown - .phui-icon-view { - color: {$bluetext}; -} - -.device button.phabricator-main-menu-search-dropdown .caret:before { - color: {$bluetext}; -} - .phabricator-main-menu-search-dropdown .caret { position: absolute; - right: 15px; - top: 5px; + right: 18px; + top: 2px; border: none; margin-top: 1px; } @@ -284,7 +277,7 @@ button.phabricator-main-menu-search-dropdown .caret:before { word-wrap: break-word; overflow-y: auto; box-shadow: {$dropshadow}; - border: 1px solid {$blueborder}; + border: 1px solid {$lightgreyborder}; border-radius: 3px; margin-left: 40px; } @@ -339,12 +332,6 @@ button.phabricator-main-menu-search-dropdown .caret:before { font-size: {$normalfontsize}; } -.device .phabricator-dark-menu .phui-list-item-type-link - .phabricator-main-search-typeahead-result { - line-height: 18px; -} - - /* - Alert --------------------------------------------------------------------- @@ -442,36 +429,6 @@ button.phabricator-main-menu-search-dropdown .caret:before { display: block; } -/* - Dark Menu ----------------------------------------------------------------- - - Styles shared between the "core" menu (left button on mobile) and - "application" menu (right button on mobile). These styles give the menu a - white-on-black appearance. - -*/ - -.device .phabricator-dark-menu, -.device .phabricator-dark-menu a.phui-list-item-href { - color: {$darkbluetext}; - -webkit-font-smoothing: antialiased; -} - -.device .phabricator-dark-menu .phui-list-item-type-label { - text-transform: uppercase; - font-size: {$normalfontsize}; - background-color: #fff; - padding: 6px 0 6px 12px; - display: block; - font-weight: bold; - color: #000; -} - -.device .phabricator-dark-menu .phui-list-item-href { - background-color: #fff; - padding: 4px 0 4px 20px; - display: block; -} - /* - Core Menu ----------------------------------------------------------------- @@ -479,10 +436,6 @@ button.phabricator-main-menu-search-dropdown .caret:before { */ -.phabricator-core-menu-profile-image { - background-size: 28px 28px; -} - .device .phabricator-search-menu { display: none; } @@ -500,12 +453,7 @@ button.phabricator-main-menu-search-dropdown .caret:before { border: 1px solid {$lightblueborder}; border-radius: 3px; box-shadow: {$dropshadow}; -} - -.device .phabricator-dark-menu .phui-list-item-type-link { - min-height: 24px; - line-height: 20px; - background: #fff; + background: {$page.background}; } .device-desktop .phabricator-application-menu { @@ -531,12 +479,6 @@ button.phabricator-main-menu-search-dropdown .caret:before { vertical-align: middle; } -.device .phabricator-dark-menu.phabricator-application-menu - .phui-list-item-icon.phui-font-fa, -.device .phabricator-dark-menu .phabricator-core-menu-icon { - display: none; -} - .device .phabricator-application-menu .phui-list-item-icon.phui-font-fa { margin: 4px 12px 4px 0; } @@ -606,29 +548,85 @@ button.phabricator-main-menu-search-dropdown .caret:before { padding-left: 12px; } +/* - User Menu ----------------------------------------------------------------- -/* - Application Menu ---------------------------------------------------------- - - Styles unique to the application menu (right button on mobile). + Styles unique to the user profile menu. */ -.device .phabricator-application-menu-expanded .phabricator-application-menu { - display: block; - position: absolute; - border: 1px solid {$blueborder}; - border-radius: 3px; - box-shadow: {$dropshadow}; - top: 42px; - right: 8px; - width: 240px; +.phabricator-core-user-menu { + float: right; + display: inline-block; + padding: 9px 24px 0 8px; + height: 35px; + position: relative; } -.device .phabricator-application-menu, -.device-desktop .phabricator-dark-menu .phui-list-item-type-label { +.phabricator-core-user-mobile-menu { display: none; } +.phabricator-core-user-menu span.phui-icon-view.phuihead-small { + height: 24px; + width: 24px; + background-size: 24px; + border-radius: 3px; + display: inline-block; + margin: 1px 0 0 0; +} + +.phabricator-core-user-menu .phui-icon-view { + color: {$hoverwhite}; + font-size: 18px; + margin: 4px 0 0 0; +} + +.phabricator-core-user-menu .caret { + position: absolute; + right: 17px; + top: 13px; + border: none; + margin: 1px; + color: {$hoverwhite}; +} + +.phabricator-core-login-button { + float: right; + display: inline-block; + padding: 4px 12px; + border-radius: 3px; + margin: 8px 6px 4px; + border: 1px solid {$hoverwhite}; + color: {$hoverwhite}; +} + +.device-desktop .phabricator-core-login-button:hover { + border: 1px solid #fff; + color: #fff; +} + +.device-desktop .phabricator-core-user-menu:hover .caret, +.device-desktop .phabricator-core-user-menu:hover .phui-icon-view { + color: #fff; +} + +.device .phabricator-core-user-menu .caret { + display: none; +} + +.device .phabricator-core-user-mobile-menu { + display: block; +} + +.device .phabricator-core-user-menu { + padding: 9px 8px 0 8px; +} + +.device .phabricator-core-user-menu .phui-icon-view { + font-size: 20px; + margin: 3px 0 0 0; +} + /* - Print --------------------------------------------------------------------- */ diff --git a/webroot/rsrc/css/application/base/notification-menu.css b/webroot/rsrc/css/application/base/notification-menu.css index 82a5aa0220..02a3d5a170 100644 --- a/webroot/rsrc/css/application/base/notification-menu.css +++ b/webroot/rsrc/css/application/base/notification-menu.css @@ -8,7 +8,7 @@ word-wrap: break-word; overflow-y: auto; box-shadow: {$dropshadow}; - border: 1px solid {$blueborder}; + border: 1px solid {$lightgreyborder}; border-radius: 3px; } diff --git a/webroot/rsrc/css/phui/phui-action-list.css b/webroot/rsrc/css/phui/phui-action-list.css index 2c82300c3b..354d3fd6e7 100644 --- a/webroot/rsrc/css/phui/phui-action-list.css +++ b/webroot/rsrc/css/phui/phui-action-list.css @@ -11,6 +11,7 @@ /* When an action list view appears inside a dropdown menu, don't hide it by default. */ display: block; + padding: 0; } .device .phabricator-action-list-view.phabricator-action-list-toggle, @@ -18,7 +19,7 @@ .phabricator-action-list-view.phabricator-action-list-toggle { display: block; width: 200px; - border: 1px solid {$lightblueborder}; + border: 1px solid {$lightgreyborder}; border-radius: 3px; position: absolute; right: 16px; @@ -58,18 +59,49 @@ .phabricator-action-view button.phabricator-action-view-item, .phabricator-action-view-item { - padding: 4px 4px 4px 28px; + padding: 4px 8px 6px 8px; display: block; text-decoration: none; color: {$darkbluetext}; } -.phabricator-action-view-label .phabricator-action-view-item { - font-size: {$normalfontsize}; +.action-has-icon button.phabricator-action-view-item, +.action-has-icon .phabricator-action-view-item { + padding: 4px 4px 4px 28px; +} + +.device-desktop .phabricator-action-view-href:hover + .phabricator-action-view-item { + text-decoration: none; + background: rgba({$alphablue}, .08); + color: {$sky}; + border-radius: 3px; +} + +.device-desktop .phabricator-action-view-href:hover + .phabricator-action-view-icon { + color: {$sky}; +} + +.device-desktop .phabricator-action-view-href.action-item-red:hover + .phabricator-action-view-item { + background-color: {$sh-redbackground}; + color: {$sh-redtext}; +} + +.device-desktop .phabricator-action-view-href.action-item-red:hover + .phabricator-action-view-icon { + color: {$red}; +} + +.phabricator-action-view-label .phabricator-action-view-item, +.phabricator-action-view-type-label .phabricator-action-view-item { + font-size: {$smallerfontsize}; font-weight: bold; color: {$bluetext}; padding: 4px 8px 6px 8px; display: block; + text-transform: uppercase; -webkit-font-smoothing: antialiased; } @@ -87,37 +119,23 @@ width: 14px; height: 14px; position: absolute; - top: 8px; + top: 7px; left: 8px; text-align: center; } -.device-desktop .phabricator-action-view:hover .phabricator-action-view-item { - text-decoration: none; - background-color: {$sky}; - color: #fff; -} - -.device-desktop .phabricator-action-view:hover .phabricator-action-view-icon { - color: #fff; -} - .phabricator-action-view-disabled .phabricator-action-view-item, .phabricator-action-view-disabled button.phabricator-action-view-item { color: {$lightgreytext}; } .phabricator-action-view-selected { - border-left: 3px solid {$sky}; - background: {$hoverblue}; + background: {$sh-violetbackground}; + border-radius: 3px; } -.phabricator-action-view-selected .phabricator-action-view-item { - padding-left: 25px; -} - -.phabricator-action-view-selected .phabricator-action-view-icon { - left: 6px; +.phabricator-action-view-selected:hover a { + text-decoration: none; } .phabricator-action-view button[disabled] { @@ -135,3 +153,8 @@ background-color: {$greybackground}; color: {$lightgreytext}; } + +.phabricator-action-view-type-divider { + margin-top: 8px; + border-top: 1px solid {$thinblueborder}; +} diff --git a/webroot/rsrc/css/phui/phui-button.css b/webroot/rsrc/css/phui/phui-button.css index 15142d3b1a..5d35688c1f 100644 --- a/webroot/rsrc/css/phui/phui-button.css +++ b/webroot/rsrc/css/phui/phui-button.css @@ -198,12 +198,12 @@ button.link:hover { .phuix-dropdown-menu { position: absolute; - width: 240px; + width: 200px; background: #fff; margin-top: -1px; - padding: 5px 0; + padding: 12px; box-shadow: {$dropshadow}; - border: 1px solid {$blueborder}; + border: 1px solid {$lightgreyborder}; border-radius: 3px; margin-bottom: 16px; } diff --git a/webroot/rsrc/css/phui/phui-document-pro.css b/webroot/rsrc/css/phui/phui-document-pro.css index 6cf0df1c68..c939b250ed 100644 --- a/webroot/rsrc/css/phui/phui-document-pro.css +++ b/webroot/rsrc/css/phui/phui-document-pro.css @@ -80,7 +80,7 @@ a.button.phui-document-toc { .phui-document-view-pro .phui-document-toc-list { margin: 8px; - border: 1px solid {$blueborder}; + border: 1px solid {$lightgreyborder}; border-radius: 3px; box-shadow: {$dropshadow}; width: 200px; diff --git a/webroot/rsrc/css/phui/phui-form-view.css b/webroot/rsrc/css/phui/phui-form-view.css index fb422f8d67..cc33808c5a 100644 --- a/webroot/rsrc/css/phui/phui-form-view.css +++ b/webroot/rsrc/css/phui/phui-form-view.css @@ -460,8 +460,7 @@ body .phui-form-view .remarkup-assist-textarea.aphront-textarea-drag-and-drop { .fancy-datepicker-core { background-color: white; - border: 1px solid {$lightblueborder}; - border-bottom: 1px solid {$blueborder}; + border: 1px solid {$lightgreyborder}; box-shadow: {$dropshadow}; border-radius: 3px; } diff --git a/webroot/rsrc/css/phui/phui-two-column-view.css b/webroot/rsrc/css/phui/phui-two-column-view.css index 0020df8b84..80e51d95da 100644 --- a/webroot/rsrc/css/phui/phui-two-column-view.css +++ b/webroot/rsrc/css/phui/phui-two-column-view.css @@ -159,24 +159,6 @@ padding: 0 12px; } -.phabricator-action-view button.phabricator-action-view-item, -.phabricator-action-view-item { - padding: 5px 4px 5px 28px; -} - -.device-desktop .phui-two-column-properties .phabricator-action-view-href:hover - .phabricator-action-view-item { - text-decoration: none; - background-color: rgba({$alphablue}, .08); - color: {$sky}; - border-radius: 3px; -} - -.device-desktop .phui-two-column-properties .phabricator-action-view-href:hover - .phabricator-action-view-icon { - color: {$sky}; -} - .phui-two-column-view .phui-property-list-section-header, .phui-two-column-view .phui-property-list-text-content { margin: 0 16px; @@ -199,6 +181,10 @@ padding: 12px; } +.phui-two-column-view .phui-oi-empty .phui-info-view { + margin: 0; +} + .phui-two-column-view .phui-side-column .phui-oi-empty .phui-info-view { margin-bottom: 0; diff --git a/webroot/rsrc/js/phuix/PHUIXActionView.js b/webroot/rsrc/js/phuix/PHUIXActionView.js index 410c23f5ab..999f80dc4b 100644 --- a/webroot/rsrc/js/phuix/PHUIXActionView.js +++ b/webroot/rsrc/js/phuix/PHUIXActionView.js @@ -77,15 +77,24 @@ JX.install('PHUIXActionView', { getNode: function() { if (!this._node) { - var attr = { - className: 'phabricator-action-view' - }; + var classes = ['phabricator-action-view']; + + if (this._href || this._handler) { + classes.push('phabricator-action-view-href'); + } + + if (this._icon) { + classes.push('action-has-icon'); + } var content = [ this._buildIconNode(), this._buildNameNode() ]; + var attr = { + className: classes.join(' ') + }; this._node = JX.$N('li', attr, content); } From d7e5a8b978ad3d864c4fbbd9adf363adabab5b4a Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 17 Jan 2017 12:46:05 -0800 Subject: [PATCH 08/31] Load global and custom profile menu items in a single query Summary: Ref T5867. Use a single query to load both personal and global items, then reorder them and add a divider if both groups have some stuff. Test Plan: Viewed menu, edited personal and global items, viewed/edited existing project menus. Reviewers: chad Reviewed By: chad Maniphest Tasks: T5867 Differential Revision: https://secure.phabricator.com/D17213 --- .../PhabricatorFavoritesApplication.php | 17 ++- .../PhabricatorFavoritesProfileMenuEngine.php | 58 +++++----- .../engine/PhabricatorProfileMenuEngine.php | 108 ++++++++++++++---- ...catorProfileMenuItemConfigurationQuery.php | 29 +++-- ...habricatorProfileMenuItemConfiguration.php | 28 +++-- 5 files changed, 162 insertions(+), 78 deletions(-) diff --git a/src/applications/favorites/application/PhabricatorFavoritesApplication.php b/src/applications/favorites/application/PhabricatorFavoritesApplication.php index 6ae45319a0..842d2e33b0 100644 --- a/src/applications/favorites/application/PhabricatorFavoritesApplication.php +++ b/src/applications/favorites/application/PhabricatorFavoritesApplication.php @@ -55,11 +55,20 @@ final class PhabricatorFavoritesApplication extends PhabricatorApplication { ->withInstalled(true) ->executeOne(); - $filter_view = id(new PhabricatorFavoritesProfileMenuEngine()) + $menu_engine = id(new PhabricatorFavoritesProfileMenuEngine()) ->setViewer($viewer) - ->setProfileObject($favorites) - ->setMenuType(PhabricatorProfileMenuEngine::MENU_COMBINED) - ->buildNavigation(); + ->setProfileObject($favorites); + + if ($viewer->getPHID()) { + $menu_engine + ->setCustomPHID($viewer->getPHID()) + ->setMenuType(PhabricatorProfileMenuEngine::MENU_COMBINED); + } else { + $menu_engine + ->setMenuType(PhabricatorProfileMenuEngine::MENU_GLOBAL); + } + + $filter_view = $menu_engine->buildNavigation(); $menu_view = $filter_view->getMenu(); $item_views = $menu_view->getItems(); diff --git a/src/applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php b/src/applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php index ff994e4793..c8f1acb31c 100644 --- a/src/applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php +++ b/src/applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php @@ -20,44 +20,40 @@ final class PhabricatorFavoritesProfileMenuEngine protected function getBuiltinProfileItems($object) { $items = array(); - $custom_phid = $this->getCustomPHID(); $viewer = $this->getViewer(); - // Built-in Global Defaults - if (!$custom_phid) { - $create_task = array( - 'name' => null, - 'formKey' => - id(new ManiphestEditEngine())->getProfileMenuItemDefault(), - ); + $create_task = array( + 'name' => null, + 'formKey' => + id(new ManiphestEditEngine())->getProfileMenuItemDefault(), + ); - $create_project = array( - 'name' => null, - 'formKey' => - id(new PhabricatorProjectEditEngine())->getProfileMenuItemDefault(), - ); + $create_project = array( + 'name' => null, + 'formKey' => + id(new PhabricatorProjectEditEngine())->getProfileMenuItemDefault(), + ); - $create_repository = array( - 'name' => null, - 'formKey' => - id(new DiffusionRepositoryEditEngine())->getProfileMenuItemDefault(), - ); + $create_repository = array( + 'name' => null, + 'formKey' => + id(new DiffusionRepositoryEditEngine())->getProfileMenuItemDefault(), + ); - $items[] = $this->newItem() - ->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_TASK) - ->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY) - ->setMenuItemProperties($create_task); + $items[] = $this->newItem() + ->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_TASK) + ->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY) + ->setMenuItemProperties($create_task); - $items[] = $this->newItem() - ->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_PROJECT) - ->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY) - ->setMenuItemProperties($create_project); + $items[] = $this->newItem() + ->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_PROJECT) + ->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY) + ->setMenuItemProperties($create_project); - $items[] = $this->newItem() - ->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_REPOSITORY) - ->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY) - ->setMenuItemProperties($create_repository); - } + $items[] = $this->newItem() + ->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_REPOSITORY) + ->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY) + ->setMenuItemProperties($create_repository); return $items; } diff --git a/src/applications/search/engine/PhabricatorProfileMenuEngine.php b/src/applications/search/engine/PhabricatorProfileMenuEngine.php index b3c341178b..7014e719b9 100644 --- a/src/applications/search/engine/PhabricatorProfileMenuEngine.php +++ b/src/applications/search/engine/PhabricatorProfileMenuEngine.php @@ -6,7 +6,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { private $profileObject; private $customPHID; private $items; - private $menuType; + private $menuType = self::MENU_GLOBAL; private $defaultItem; private $controller; private $navigation; @@ -15,6 +15,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { const MENU_GLOBAL = 'global'; const MENU_PERSONAL = 'personal'; const MENU_COMBINED = 'menu'; + const ITEM_CUSTOM_DIVIDER = 'engine.divider'; public function setViewer(PhabricatorUser $viewer) { $this->viewer = $viewer; @@ -82,9 +83,16 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { } abstract protected function getItemURI($path); - abstract protected function isMenuEngineConfigurable(); + abstract protected function getBuiltinProfileItems($object); + + protected function getBuiltinCustomProfileItems( + $object, + $custom_phid) { + return array(); + } + public function buildResponse() { $controller = $this->getController(); @@ -230,6 +238,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { ->setBaseURI(new PhutilURI($this->getItemURI(''))); $menu_items = $this->getItems(); + $filtered_items = array(); foreach ($menu_items as $menu_item) { if ($menu_item->isDisabled()) { @@ -294,23 +303,26 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { $object = $this->getProfileObject(); $items = $this->loadBuiltinProfileItems(); - $menu = $this->getMenuType(); - if ($this->getCustomPHID()) { - $stored_items = id(new PhabricatorProfileMenuItemConfigurationQuery()) - ->setViewer($viewer) - ->withProfilePHIDs(array($object->getPHID())) - ->withCustomPHIDs(array($this->getCustomPHID())) - ->setMenuType($menu) - ->execute(); - } else { - $stored_items = id(new PhabricatorProfileMenuItemConfigurationQuery()) - ->setViewer($viewer) - ->withProfilePHIDs(array($object->getPHID())) - ->setMenuType($menu) - ->execute(); + $query = id(new PhabricatorProfileMenuItemConfigurationQuery()) + ->setViewer($viewer) + ->withProfilePHIDs(array($object->getPHID())); + + $menu_type = $this->getMenuType(); + switch ($menu_type) { + case self::MENU_GLOBAL: + $query->withCustomPHIDs(array(), true); + break; + case self::MENU_PERSONAL: + $query->withCustomPHIDs(array($this->getCustomPHID()), false); + break; + case self::MENU_COMBINED: + $query->withCustomPHIDs(array($this->getCustomPHID()), true); + break; } + $stored_items = $query->execute(); + foreach ($stored_items as $stored_item) { $impl = $stored_item->getMenuItem(); $impl->setViewer($viewer); @@ -339,12 +351,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { } } - $items = msort($items, 'getSortKey'); - - // Normalize keys since callers shouldn't rely on this array being - // partially keyed. - $items = array_values($items); - + $items = $this->arrangeItems($items); // Make sure exactly one valid item is marked as default. $default = null; @@ -377,7 +384,26 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { private function loadBuiltinProfileItems() { $object = $this->getProfileObject(); - $builtins = $this->getBuiltinProfileItems($object); + + $menu_type = $this->getMenuType(); + switch ($menu_type) { + case self::MENU_GLOBAL: + $builtins = $this->getBuiltinProfileItems($object); + break; + case self::MENU_PERSONAL: + $builtins = $this->getBuiltinCustomProfileItems( + $object, + $this->getCustomPHID()); + break; + case self::MENU_COMBINED: + $builtins = array(); + $builtins[] = $this->getBuiltinCustomProfileItems( + $object, + $this->getCustomPHID()); + $builtins[] = $this->getBuiltinProfileItems($object); + $builtins = array_mergev($builtins); + break; + } $items = PhabricatorProfileMenuItem::getAllMenuItems(); $viewer = $this->getViewer(); @@ -990,4 +1016,40 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { return $this; } + private function arrangeItems(array $items) { + // Sort the items. + $items = msortv($items, 'getSortVector'); + + // If we have some global items and some custom items and are in "combined" + // mode, put a hard-coded divider item between them. + if ($this->getMenuType() == self::MENU_COMBINED) { + $list = array(); + $seen_custom = false; + $seen_global = false; + foreach ($items as $item) { + if ($item->getCustomPHID()) { + $seen_custom = true; + } else { + if ($seen_custom && !$seen_global) { + $list[] = $this->newItem() + ->setBuiltinKey(self::ITEM_CUSTOM_DIVIDER) + ->setMenuItemKey(PhabricatorDividerProfileMenuItem::MENUITEMKEY) + ->attachMenuItem( + new PhabricatorDividerProfileMenuItem()); + } + $seen_global = true; + } + $list[] = $item; + } + $items = $list; + } + + // Normalize keys since callers shouldn't rely on this array being + // partially keyed. + $items = array_values($items); + + return $items; + } + + } diff --git a/src/applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php b/src/applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php index 2256be446f..83a84ac306 100644 --- a/src/applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php +++ b/src/applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php @@ -7,7 +7,7 @@ final class PhabricatorProfileMenuItemConfigurationQuery private $phids; private $profilePHIDs; private $customPHIDs; - private $menuType; + private $includeGlobal; public function withIDs(array $ids) { $this->ids = $ids; @@ -24,13 +24,9 @@ final class PhabricatorProfileMenuItemConfigurationQuery return $this; } - public function withCustomPHIDs(array $phids) { + public function withCustomPHIDs(array $phids, $include_global = false) { $this->customPHIDs = $phids; - return $this; - } - - public function setMenuType($type) { - $this->menuType = $type; + $this->includeGlobal = $include_global; return $this; } @@ -67,10 +63,21 @@ final class PhabricatorProfileMenuItemConfigurationQuery } if ($this->customPHIDs !== null) { - $where[] = qsprintf( - $conn, - 'customPHID IN (%Ls)', - $this->customPHIDs); + if ($this->customPHIDs && $this->includeGlobal) { + $where[] = qsprintf( + $conn, + 'customPHID IN (%Ls) OR customPHID IS NULL', + $this->customPHIDs); + } else if ($this->customPHIDs) { + $where[] = qsprintf( + $conn, + 'customPHID IN (%Ls)', + $this->customPHIDs); + } else { + $where[] = qsprintf( + $conn, + 'customPHID IS NULL'); + } } return $where; diff --git a/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php b/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php index 78fc380604..943474669d 100644 --- a/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php +++ b/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php @@ -126,18 +126,28 @@ final class PhabricatorProfileMenuItemConfiguration return $this->getMenuItem()->willBuildNavigationItems($items); } - public function getSortKey() { - $order = $this->getMenuItemOrder(); - if ($order === null) { - $order = 'Z'; + public function getSortVector() { + // Sort custom items above global items. + if ($this->getCustomPHID()) { + $is_global = 0; } else { - $order = sprintf('%020d', $order); + $is_global = 1; } - return sprintf( - '~%s%020d', - $order, - $this->getID()); + // Sort items with an explicit order above items without an explicit order, + // so any newly created builtins go to the bottom. + $order = $this->getMenuItemOrder(); + if ($order !== null) { + $has_order = 0; + } else { + $has_order = 1; + } + + return id(new PhutilSortVector()) + ->addInt($is_global) + ->addInt($has_order) + ->addInt((int)$order) + ->addInt((int)$this->getID()); } public function isDisabled() { From db65f828ee697a0bfee8f8c2c291f98c2885053c Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 17 Jan 2017 14:52:57 -0800 Subject: [PATCH 09/31] Fix $classes not imploding properly in list view Summary: Fixes the persistent chat hyperlinks showing. Test Plan: Open persistent chat, no longer see the hyperlinks showing. Close and open chat. Edit room. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17216 --- src/view/phui/PHUIListItemView.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/phui/PHUIListItemView.php b/src/view/phui/PHUIListItemView.php index 95e4947162..0ca942dd6a 100644 --- a/src/view/phui/PHUIListItemView.php +++ b/src/view/phui/PHUIListItemView.php @@ -249,7 +249,7 @@ final class PHUIListItemView extends AphrontTagView { $name = phutil_tag( 'span', array( - 'class' => $classes, + 'class' => implode(' ', $classes), ), array( $this->name, From a886969c480fdcb0fad3656668bab88368fb342c Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 17 Jan 2017 13:59:56 -0800 Subject: [PATCH 10/31] Make documentation items in user menu update as you navigate in Quicksand Summary: Ref T5867. I sure love Javascript. Test Plan: Navigated between Home, Diffusion and Differential, opening the user profile menu. Saw appropraite help items. Reviewers: chad Reviewed By: chad Maniphest Tasks: T5867 Differential Revision: https://secure.phabricator.com/D17214 --- resources/celerity/map.php | 33 ++++++----- .../base/PhabricatorApplication.php | 17 +++++- .../PhabricatorHomeApplication.php | 41 +++++++------ src/view/layout/PhabricatorActionView.php | 2 +- src/view/page/PhabricatorStandardPageView.php | 29 ++++------ src/view/phui/PHUIButtonView.php | 12 +++- .../aphlict/behavior-aphlict-dropdown.js | 18 ------ webroot/rsrc/js/core/behavior-user-menu.js | 57 +++++++++++++++++++ 8 files changed, 139 insertions(+), 70 deletions(-) create mode 100644 webroot/rsrc/js/core/behavior-user-menu.js diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 0102a54ed8..e97050fdbc 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -10,7 +10,7 @@ return array( 'conpherence.pkg.css' => '0b64e988', 'conpherence.pkg.js' => '6249a1cf', 'core.pkg.css' => '85f51b68', - 'core.pkg.js' => '2c684890', + 'core.pkg.js' => '666970d7', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '9535a7e6', 'differential.pkg.js' => 'ddfeb49b', @@ -374,7 +374,7 @@ return array( 'rsrc/image/texture/table_header_hover.png' => '038ec3b9', 'rsrc/image/texture/table_header_tall.png' => 'd56b434f', 'rsrc/js/application/aphlict/Aphlict.js' => '5359e785', - 'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => '2a171a9d', + 'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => 'caade6f2', 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'fb20ac8d', 'rsrc/js/application/aphlict/behavior-aphlict-status.js' => '5e2634b9', 'rsrc/js/application/aphlict/behavior-desktop-notifications-control.js' => 'edd1ba66', @@ -530,6 +530,7 @@ return array( 'rsrc/js/core/behavior-toggle-class.js' => '92b9ec77', 'rsrc/js/core/behavior-tokenizer.js' => 'b3a4b884', 'rsrc/js/core/behavior-tooltip.js' => '42fcb747', + 'rsrc/js/core/behavior-user-menu.js' => '31420f77', 'rsrc/js/core/behavior-watch-anchor.js' => '9f36c42d', 'rsrc/js/core/behavior-workflow.js' => '0a3f3021', 'rsrc/js/core/phtize.js' => 'd254d646', @@ -595,7 +596,7 @@ return array( 'inline-comment-summary-css' => '51efda3a', 'javelin-aphlict' => '5359e785', 'javelin-behavior' => '61cbc29a', - 'javelin-behavior-aphlict-dropdown' => '2a171a9d', + 'javelin-behavior-aphlict-dropdown' => 'caade6f2', 'javelin-behavior-aphlict-listen' => 'fb20ac8d', 'javelin-behavior-aphlict-status' => '5e2634b9', 'javelin-behavior-aphront-basic-tokenizer' => 'b3a4b884', @@ -719,6 +720,7 @@ return array( 'javelin-behavior-toggle-widget' => '3dbf94d5', 'javelin-behavior-typeahead-browse' => '635de1ec', 'javelin-behavior-typeahead-search' => '93d0c9e3', + 'javelin-behavior-user-menu' => '31420f77', 'javelin-behavior-view-placeholder' => '47830651', 'javelin-behavior-workflow' => '0a3f3021', 'javelin-color' => '7e41274a', @@ -1114,17 +1116,6 @@ return array( 'javelin-install', 'javelin-util', ), - '2a171a9d' => array( - 'javelin-behavior', - 'javelin-request', - 'javelin-stratcom', - 'javelin-vector', - 'javelin-dom', - 'javelin-uri', - 'javelin-behavior-device', - 'phabricator-title', - 'phabricator-favicon', - ), '2b8de964' => array( 'javelin-install', 'javelin-util', @@ -1144,6 +1135,9 @@ return array( '2ee659ce' => array( 'javelin-install', ), + '31420f77' => array( + 'javelin-behavior', + ), '320810c8' => array( 'javelin-install', 'javelin-dom', @@ -1999,6 +1993,17 @@ return array( 'javelin-stratcom', 'phabricator-phtize', ), + 'caade6f2' => array( + 'javelin-behavior', + 'javelin-request', + 'javelin-stratcom', + 'javelin-vector', + 'javelin-dom', + 'javelin-uri', + 'javelin-behavior-device', + 'phabricator-title', + 'phabricator-favicon', + ), 'ccf1cbf8' => array( 'javelin-install', 'javelin-dom', diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php index 2136a3e4b0..e50045b0e9 100644 --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -175,7 +175,9 @@ abstract class PhabricatorApplication foreach ($articles as $article) { $item = id(new PhabricatorActionView()) ->setName($article['name']) - ->setHref($article['href']); + ->setHref($article['href']) + ->addSigil('help-item') + ->setOpenInNewWindow(true); $items[] = $item; } } @@ -189,12 +191,21 @@ abstract class PhabricatorApplication $href = '/applications/mailcommands/'.$class.'/'.$key.'/'; $item = id(new PhabricatorActionView()) ->setName($spec['name']) - ->setHref($href); + ->setHref($href) + ->addSigil('help-item') + ->setOpenInNewWindow(true); $items[] = $item; } } - return $items; + if ($items) { + $divider = id(new PhabricatorActionView()) + ->addSigil('help-item') + ->setType(PhabricatorActionView::TYPE_DIVIDER); + array_unshift($items, $divider); + } + + return array_values($items); } public function getHelpDocumentationArticles(PhabricatorUser $viewer) { diff --git a/src/applications/home/application/PhabricatorHomeApplication.php b/src/applications/home/application/PhabricatorHomeApplication.php index 9364879e18..d3823dab85 100644 --- a/src/applications/home/application/PhabricatorHomeApplication.php +++ b/src/applications/home/application/PhabricatorHomeApplication.php @@ -2,8 +2,6 @@ final class PhabricatorHomeApplication extends PhabricatorApplication { - private $application; - const DASHBOARD_DEFAULT = 'dashboard:default'; public function getBaseURI() { @@ -53,25 +51,40 @@ final class PhabricatorHomeApplication extends PhabricatorApplication { } $image = $viewer->getProfileImageURI(); - if ($controller) { - $this->application = $controller->getCurrentApplication(); - } $profile_image = id(new PHUIIconView()) ->setImage($image) ->setHeadSize(PHUIIconView::HEAD_SMALL); + if ($controller) { + $application = $controller->getCurrentApplication(); + } else { + $application = null; + } + $dropdown_menu = $this->renderUserDropdown($viewer, $application); + + $menu_id = celerity_generate_unique_node_id(); + + Javelin::initBehavior( + 'user-menu', + array( + 'menuID' => $menu_id, + 'menu' => $dropdown_menu->getDropdownMenuMetadata(), + )); + return id(new PHUIButtonView()) + ->setID($menu_id) ->setTag('a') ->setHref('/p/'.$viewer->getUsername().'/') ->setIcon($profile_image) ->addClass('phabricator-core-user-menu') - ->setNoCSS(true) - ->setDropdown(true) - ->setDropdownMenu($this->renderUserDropdown($viewer)); + ->setHasCaret(true) + ->setNoCSS(true); } - private function renderUserDropdown(PhabricatorUser $viewer) { + private function renderUserDropdown( + PhabricatorUser $viewer, + $application) { $view = id(new PhabricatorActionListView()) ->setViewer($viewer); @@ -98,16 +111,10 @@ final class PhabricatorHomeApplication extends PhabricatorApplication { ->setHref('/people/manage/'.$viewer->getID().'/')); // Help Menus - if ($this->application) { - $application = $this->application; + if ($application) { $help_links = $application->getHelpMenuItems($viewer); if ($help_links) { - $view->addAction( - id(new PhabricatorActionView()) - ->setType(PhabricatorActionView::TYPE_DIVIDER)); - foreach ($help_links as $link) { - $link->setOpenInNewWindow(true); $view->addAction($link); } } @@ -116,11 +123,13 @@ final class PhabricatorHomeApplication extends PhabricatorApplication { // Logout Menu $view->addAction( id(new PhabricatorActionView()) + ->addSigil('logout-item') ->setType(PhabricatorActionView::TYPE_DIVIDER)); $view->addAction( id(new PhabricatorActionView()) ->setName(pht('Log Out %s', $viewer->getUsername())) + ->addSigil('logout-item') ->setHref('/logout/') ->setWorkflow(true)); diff --git a/src/view/layout/PhabricatorActionView.php b/src/view/layout/PhabricatorActionView.php index 755ed892f0..74e3c0b12d 100644 --- a/src/view/layout/PhabricatorActionView.php +++ b/src/view/layout/PhabricatorActionView.php @@ -278,7 +278,7 @@ final class PhabricatorActionView extends AphrontView { array($icon, $this->name, $caret)); } } else { - $item = phutil_tag( + $item = javelin_tag( 'span', array( 'class' => 'phabricator-action-view-item', diff --git a/src/view/page/PhabricatorStandardPageView.php b/src/view/page/PhabricatorStandardPageView.php index 96e43e81fe..67c4dc188c 100644 --- a/src/view/page/PhabricatorStandardPageView.php +++ b/src/view/page/PhabricatorStandardPageView.php @@ -767,22 +767,6 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView ->setViewer($viewer); $dropdown_query->execute(); - $rendered_dropdowns = array(); - $applications = array( - 'PhabricatorHomeApplication', - ); - foreach ($applications as $application_class) { - if (!PhabricatorApplication::isClassInstalledForViewer( - $application_class, - $viewer)) { - continue; - } - $application = PhabricatorApplication::getByClass($application_class); - $menu = $application->buildMainMenuExtraNodes($viewer, $controller); - // TODO: Doesn't work with Quicksand active. - $rendered_dropdowns[$application_class] = hsprintf('%s', $menu); - } - $hisec_warning_config = $this->getHighSecurityWarningConfig(); $console_config = null; @@ -798,6 +782,7 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView $application_class = null; $application_search_icon = null; + $application_help = null; $controller = $this->getController(); if ($controller) { $application = $controller->getCurrentApplication(); @@ -806,6 +791,16 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView if ($application->getApplicationSearchDocumentTypes()) { $application_search_icon = $application->getIcon(); } + + $help_items = $application->getHelpMenuItems($viewer); + if ($help_items) { + $help_list = id(new PhabricatorActionListView()) + ->setViewer($viewer); + foreach ($help_items as $help_item) { + $help_list->addAction($help_item); + } + $application_help = $help_list->getDropdownMenuMetadata(); + } } } @@ -817,11 +812,11 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView $dropdown_query->getConpherenceData(), ), 'globalDragAndDrop' => $upload_enabled, - 'aphlictDropdowns' => $rendered_dropdowns, 'hisecWarningConfig' => $hisec_warning_config, 'consoleConfig' => $console_config, 'applicationClass' => $application_class, 'applicationSearchIcon' => $application_search_icon, + 'helpItems' => $application_help, ) + $this->buildAphlictListenConfigData(); } diff --git a/src/view/phui/PHUIButtonView.php b/src/view/phui/PHUIButtonView.php index ffe83500d3..c4ee7a190c 100644 --- a/src/view/phui/PHUIButtonView.php +++ b/src/view/phui/PHUIButtonView.php @@ -28,6 +28,7 @@ final class PHUIButtonView extends AphrontTagView { private $name; private $tooltip; private $noCSS; + private $hasCaret; public function setName($name) { $this->name = $name; @@ -93,6 +94,15 @@ final class PHUIButtonView extends AphrontTagView { return $this; } + public function setHasCaret($has_caret) { + $this->hasCaret = $has_caret; + return $this; + } + + public function getHasCaret() { + return $this->hasCaret; + } + public function setIcon($icon, $first = true) { if (!($icon instanceof PHUIIconView)) { $icon = id(new PHUIIconView()) @@ -201,7 +211,7 @@ final class PHUIButtonView extends AphrontTagView { } $caret = null; - if ($this->dropdown) { + if ($this->dropdown || $this->getHasCaret()) { $caret = phutil_tag('span', array('class' => 'caret'), ''); } diff --git a/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js b/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js index f12be7a22b..21db1d94d5 100644 --- a/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js +++ b/webroot/rsrc/js/application/aphlict/behavior-aphlict-dropdown.js @@ -91,24 +91,6 @@ JX.behavior('aphlict-dropdown', function(config, statics) { null, function (e) { var data = e.getData(); - if (config.local && config.applicationClass) { - var local_dropdowns = data.newResponse.aphlictDropdowns; - if (local_dropdowns[config.applicationClass]) { - JX.DOM.replace( - dropdown, - JX.$H(local_dropdowns[config.applicationClass])); - dropdown = JX.$(config.dropdownID); - if (dropdown.childNodes.length === 0) { - JX.DOM.hide(bubble); - } else { - JX.DOM.show(bubble); - } - } else { - JX.DOM.hide(bubble); - } - return; - } - if (!data.fromServer) { return; } diff --git a/webroot/rsrc/js/core/behavior-user-menu.js b/webroot/rsrc/js/core/behavior-user-menu.js new file mode 100644 index 0000000000..b74b9d36ab --- /dev/null +++ b/webroot/rsrc/js/core/behavior-user-menu.js @@ -0,0 +1,57 @@ +/** + * @provides javelin-behavior-user-menu + * @requires javelin-behavior + */ + +JX.behavior('user-menu', function(config) { + var node = JX.$(config.menuID); + var list = JX.$H(config.menu.items).getFragment().firstChild; + + var menu = new JX.PHUIXDropdownMenu(node); + + menu.listen('open', function() { + menu.setContent(list); + }); + + // When the user navigates to a new page, we may need to update the links + // to documentation in the menu. + JX.Stratcom.listen('quicksand-redraw', null, function(e) { + var data = e.getData(); + + var new_help = data.newResponse.helpItems; + var nodes; + if (new_help) { + nodes = JX.$H(new_help.items).getFragment().firstChild.children; + } else { + nodes = []; + } + + var ii; + + var tail = []; + for (ii = list.children.length - 1; ii >= 0; ii--) { + var node = list.children[ii]; + + // Remove any old help items. + if (JX.Stratcom.hasSigil(node.firstChild, 'help-item')) { + JX.DOM.remove(node); + } + + // Place the logout items aside, if any exist. + if (JX.Stratcom.hasSigil(node.firstChild, 'logout-item')) { + JX.DOM.remove(node); + tail.push(node); + } + } + + while (nodes.length) { + list.appendChild(nodes[0]); + } + + tail.reverse(); + for (ii = 0; ii < tail.length; ii++) { + list.appendChild(tail[ii]); + } + }); + +}); From 9d3f09ab478e44d30b6a58688c470239b44efb02 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 17 Jan 2017 14:17:24 -0800 Subject: [PATCH 11/31] Modularize global quick create builtin items Summary: Ref T5867. Instead of hard-coding projects, tasks and repositories, let EditEngines say "I want a quick create item" so third-party code can also hook into the menu without upstream changes. Test Plan: Saw same default items in menu. Reviewers: chad Reviewed By: chad Maniphest Tasks: T5867 Differential Revision: https://secure.phabricator.com/D17215 --- src/__phutil_library_map__.php | 2 - .../editor/DiffusionRepositoryEditEngine.php | 4 + .../PhabricatorFavoritesConstants.php | 11 --- .../PhabricatorFavoritesProfileMenuEngine.php | 45 ++++----- .../maniphest/editor/ManiphestEditEngine.php | 4 + .../engine/PhabricatorProjectEditEngine.php | 4 + .../editengine/PhabricatorEditEngine.php | 93 +++++-------------- 7 files changed, 51 insertions(+), 112 deletions(-) delete mode 100644 src/applications/favorites/constants/PhabricatorFavoritesConstants.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index ee6508226a..1e1ae93e85 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2668,7 +2668,6 @@ phutil_register_library_map(array( 'PhabricatorFactSpec' => 'applications/fact/spec/PhabricatorFactSpec.php', 'PhabricatorFactUpdateIterator' => 'applications/fact/extract/PhabricatorFactUpdateIterator.php', 'PhabricatorFavoritesApplication' => 'applications/favorites/application/PhabricatorFavoritesApplication.php', - 'PhabricatorFavoritesConstants' => 'applications/favorites/constants/PhabricatorFavoritesConstants.php', 'PhabricatorFavoritesController' => 'applications/favorites/controller/PhabricatorFavoritesController.php', 'PhabricatorFavoritesMainController' => 'applications/favorites/controller/PhabricatorFavoritesMainController.php', 'PhabricatorFavoritesMenuItemController' => 'applications/favorites/controller/PhabricatorFavoritesMenuItemController.php', @@ -7683,7 +7682,6 @@ phutil_register_library_map(array( 'PhabricatorFactSpec' => 'Phobject', 'PhabricatorFactUpdateIterator' => 'PhutilBufferedIterator', 'PhabricatorFavoritesApplication' => 'PhabricatorApplication', - 'PhabricatorFavoritesConstants' => 'PhabricatorFavoritesController', 'PhabricatorFavoritesController' => 'PhabricatorController', 'PhabricatorFavoritesMainController' => 'PhabricatorFavoritesController', 'PhabricatorFavoritesMenuItemController' => 'PhabricatorFavoritesController', diff --git a/src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php b/src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php index 933cdbb597..4f45357956 100644 --- a/src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php +++ b/src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php @@ -20,6 +20,10 @@ final class DiffusionRepositoryEditEngine return false; } + public function isDefaultQuickCreateEngine() { + return true; + } + public function getEngineName() { return pht('Repositories'); } diff --git a/src/applications/favorites/constants/PhabricatorFavoritesConstants.php b/src/applications/favorites/constants/PhabricatorFavoritesConstants.php deleted file mode 100644 index 2beb4fd1cc..0000000000 --- a/src/applications/favorites/constants/PhabricatorFavoritesConstants.php +++ /dev/null @@ -1,11 +0,0 @@ -getViewer(); - $create_task = array( - 'name' => null, - 'formKey' => - id(new ManiphestEditEngine())->getProfileMenuItemDefault(), - ); + $engines = PhabricatorEditEngine::getAllEditEngines(); + $engines = msortv($engines, 'getQuickCreateOrderVector'); - $create_project = array( - 'name' => null, - 'formKey' => - id(new PhabricatorProjectEditEngine())->getProfileMenuItemDefault(), - ); + foreach ($engines as $engine) { + foreach ($engine->getDefaultQuickCreateFormKeys() as $form_key) { + $form_hash = PhabricatorHash::digestForIndex($form_key); + $builtin_key = "editengine.form({$form_hash})"; - $create_repository = array( - 'name' => null, - 'formKey' => - id(new DiffusionRepositoryEditEngine())->getProfileMenuItemDefault(), - ); + $properties = array( + 'name' => null, + 'formKey' => $form_key, + ); - $items[] = $this->newItem() - ->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_TASK) - ->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY) - ->setMenuItemProperties($create_task); - - $items[] = $this->newItem() - ->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_PROJECT) - ->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY) - ->setMenuItemProperties($create_project); - - $items[] = $this->newItem() - ->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_REPOSITORY) - ->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY) - ->setMenuItemProperties($create_repository); + $items[] = $this->newItem() + ->setBuiltinKey($builtin_key) + ->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY) + ->setMenuItemProperties($properties); + } + } return $items; } diff --git a/src/applications/maniphest/editor/ManiphestEditEngine.php b/src/applications/maniphest/editor/ManiphestEditEngine.php index 8e5893a9b8..0433e8200a 100644 --- a/src/applications/maniphest/editor/ManiphestEditEngine.php +++ b/src/applications/maniphest/editor/ManiphestEditEngine.php @@ -21,6 +21,10 @@ final class ManiphestEditEngine return 'PhabricatorManiphestApplication'; } + public function isDefaultQuickCreateEngine() { + return true; + } + protected function newEditableObject() { return ManiphestTask::initializeNewTask($this->getViewer()); } diff --git a/src/applications/project/engine/PhabricatorProjectEditEngine.php b/src/applications/project/engine/PhabricatorProjectEditEngine.php index 760fad39d0..7a0c11be0e 100644 --- a/src/applications/project/engine/PhabricatorProjectEditEngine.php +++ b/src/applications/project/engine/PhabricatorProjectEditEngine.php @@ -26,6 +26,10 @@ final class PhabricatorProjectEditEngine return $this->milestoneProject; } + public function isDefaultQuickCreateEngine() { + return true; + } + public function getEngineName() { return pht('Projects'); } diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php index 434fcc5091..65901e1294 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngine.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php @@ -77,6 +77,29 @@ abstract class PhabricatorEditEngine return true; } + public function isDefaultQuickCreateEngine() { + return false; + } + + public function getDefaultQuickCreateFormKeys() { + $keys = array(); + + if ($this->isDefaultQuickCreateEngine()) { + $keys[] = self::EDITENGINECONFIG_DEFAULT; + } + + foreach ($keys as $idx => $key) { + $keys[$idx] = $this->getEngineKey().'/'.$key; + } + + return $keys; + } + + public function getQuickCreateOrderVector() { + return id(new PhutilSortVector()) + ->addString($this->getObjectCreateShortText()); + } + /** * Force the engine to edit a particular object. */ @@ -107,10 +130,6 @@ abstract class PhabricatorEditEngine return $this->hideHeader; } - public function getProfileMenuItemDefault() { - return $this->getEngineKey().'/'.self::EDITENGINECONFIG_DEFAULT; - } - /* -( Managing Fields )---------------------------------------------------- */ @@ -283,14 +302,6 @@ abstract class PhabricatorEditEngine } - /** - * @task text - */ - protected function getQuickCreateMenuHeaderText() { - return $this->getObjectCreateShortText(); - } - - /** * Return a human-readable header describing what this engine is used to do, * like "Configure Maniphest Task Forms". @@ -2100,50 +2111,6 @@ abstract class PhabricatorEditEngine return $application->getIcon(); } - public function hasQuickCreateActions() { - if (!$this->isEngineConfigurable()) { - return false; - } - - return true; - } - - public function newQuickCreateActions(array $configs) { - $items = array(); - - if (!$configs) { - return array(); - } - - // If the viewer is logged in and can't create objects, don't show the - // menu item. If they're logged out, we assume they could create objects - // if they logged in, so we show the item as a hint about how to - // accomplish the action. - if ($this->getViewer()->isLoggedIn()) { - if (!$this->hasCreateCapability()) { - return array(); - } - } - - if (count($configs) == 1) { - $config = head($configs); - $items[] = $this->newQuickCreateAction($config); - } else { - $group_name = $this->getQuickCreateMenuHeaderText(); - - $items[] = id(new PHUIListItemView()) - ->setType(PHUIListItemView::TYPE_LABEL) - ->setName($group_name); - - foreach ($configs as $config) { - $items[] = $this->newQuickCreateAction($config) - ->setIndented(true); - } - } - - return $items; - } - private function loadUsableConfigurationsForCreate() { $viewer = $this->getViewer(); @@ -2159,20 +2126,6 @@ abstract class PhabricatorEditEngine return $configs; } - private function newQuickCreateAction( - PhabricatorEditEngineConfiguration $config) { - - $item_name = $config->getName(); - $item_icon = $config->getIcon(); - $form_key = $config->getIdentifier(); - $item_uri = $this->getEditURI(null, "form/{$form_key}/"); - - return id(new PHUIListItemView()) - ->setName($item_name) - ->setIcon($item_icon) - ->setHref($item_uri); - } - protected function getValidationExceptionShortMessage( PhabricatorApplicationTransactionValidationException $ex, PhabricatorEditField $field) { From 2d4eb460abb2ba34a944962c7cfea5741e099ff9 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 17 Jan 2017 19:15:09 -0800 Subject: [PATCH 12/31] Fix MenuItem names not getting attached Summary: - Attach objects when showing configuration screen - Fix "Forms" to make more sense - Alter EditEngine title to load correct name by loading object Fixes T12116 Test Plan: Load up Apps/Projects/Forms on a configure menu, see proper names Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12116 Differential Revision: https://secure.phabricator.com/D17217 --- .../search/editor/PhabricatorProfileMenuEditEngine.php | 1 + .../search/engine/PhabricatorProfileMenuEngine.php | 6 ++++++ .../menuitem/PhabricatorEditEngineProfileMenuItem.php | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/applications/search/editor/PhabricatorProfileMenuEditEngine.php b/src/applications/search/editor/PhabricatorProfileMenuEditEngine.php index 70ba141967..176938afb6 100644 --- a/src/applications/search/editor/PhabricatorProfileMenuEditEngine.php +++ b/src/applications/search/editor/PhabricatorProfileMenuEditEngine.php @@ -109,6 +109,7 @@ final class PhabricatorProfileMenuEditEngine } protected function getObjectEditTitleText($object) { + $object->willBuildNavigationItems(array($object)); return pht('Edit Menu Item: %s', $object->getDisplayName()); } diff --git a/src/applications/search/engine/PhabricatorProfileMenuEngine.php b/src/applications/search/engine/PhabricatorProfileMenuEngine.php index 7014e719b9..6157d5f657 100644 --- a/src/applications/search/engine/PhabricatorProfileMenuEngine.php +++ b/src/applications/search/engine/PhabricatorProfileMenuEngine.php @@ -551,6 +551,12 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { $viewer = $this->getViewer(); $object = $this->getProfileObject(); + $filtered_groups = mgroup($items, 'getMenuItemKey'); + foreach ($filtered_groups as $group) { + $first_item = head($group); + $first_item->willBuildNavigationItems($group); + } + PhabricatorPolicyFilter::requireCapability( $viewer, $object, diff --git a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php index 6622bb7506..374fe10366 100644 --- a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php @@ -12,7 +12,7 @@ final class PhabricatorEditEngineProfileMenuItem } public function getMenuItemTypeName() { - return pht('Forms'); + return pht('Form'); } public function canAddToObject($object) { From 0513a242352ee00f0486d93ab7c10c9708741885 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 18 Jan 2017 05:57:03 -0800 Subject: [PATCH 13/31] Fix a bad constant in "audit.query" Summary: Fixes T12117. I typed or copy/pasted this constant wrong while refactoring during T10978. Test Plan: Called `audit.query`. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12117 Differential Revision: https://secure.phabricator.com/D17218 --- src/applications/audit/conduit/AuditQueryConduitAPIMethod.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/audit/conduit/AuditQueryConduitAPIMethod.php b/src/applications/audit/conduit/AuditQueryConduitAPIMethod.php index 0f2fe473f5..d65c939a61 100644 --- a/src/applications/audit/conduit/AuditQueryConduitAPIMethod.php +++ b/src/applications/audit/conduit/AuditQueryConduitAPIMethod.php @@ -75,7 +75,7 @@ final class AuditQueryConduitAPIMethod extends AuditConduitAPIMethod { PhabricatorAuditCommitStatusConstants::CONCERN_RAISED, ), self::AUDIT_LEGACYSTATUS_ACCEPTED => array( - PhabricatorAuditCommitStatusConstants::CONCERN_ACCEPTED, + PhabricatorAuditCommitStatusConstants::FULLY_AUDITED, ), self::AUDIT_LEGACYSTATUS_PARTIAL => array( PhabricatorAuditCommitStatusConstants::PARTIALLY_AUDITED, From b21cd24341c6552a3fbd21305ca682a161129a6b Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 18 Jan 2017 06:05:25 -0800 Subject: [PATCH 14/31] When Favorites is uninstalled or not visible to the viewer, hide the menu Summary: Ref T5867. The `executeOne()` currently raises a policy exception if the application isn't visible to the viewer, or we fatal if the application has been uninstalled. Test Plan: - Viewed pages with the application uninstalled, saw working pages with no favorites menu. - Viewed pages with the application restricted, saw working pages with no favorites menu. Reviewers: chad Reviewed By: chad Maniphest Tasks: T5867 Differential Revision: https://secure.phabricator.com/D17219 --- .../PhabricatorFavoritesApplication.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/applications/favorites/application/PhabricatorFavoritesApplication.php b/src/applications/favorites/application/PhabricatorFavoritesApplication.php index 842d2e33b0..958355a2b5 100644 --- a/src/applications/favorites/application/PhabricatorFavoritesApplication.php +++ b/src/applications/favorites/application/PhabricatorFavoritesApplication.php @@ -36,6 +36,11 @@ final class PhabricatorFavoritesApplication extends PhabricatorApplication { PhabricatorUser $viewer, PhabricatorController $controller = null) { + $dropdown = $this->renderFavoritesDropdown($viewer); + if (!$dropdown) { + return null; + } + return id(new PHUIButtonView()) ->setTag('a') ->setHref('#') @@ -43,17 +48,21 @@ final class PhabricatorFavoritesApplication extends PhabricatorApplication { ->addClass('phabricator-core-user-menu') ->setNoCSS(true) ->setDropdown(true) - ->setDropdownMenu($this->renderFavoritesDropdown($viewer)); + ->setDropdownMenu($dropdown); } private function renderFavoritesDropdown(PhabricatorUser $viewer) { - $application = __CLASS__; - $favorites = id(new PhabricatorApplicationQuery()) + + $applications = id(new PhabricatorApplicationQuery()) ->setViewer($viewer) ->withClasses(array($application)) ->withInstalled(true) - ->executeOne(); + ->execute(); + $favorites = head($applications); + if (!$favorites) { + return null; + } $menu_engine = id(new PhabricatorFavoritesProfileMenuEngine()) ->setViewer($viewer) From a3b067291f85b41cd192b1b8cb78753988d1d62c Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 18 Jan 2017 05:56:41 -0800 Subject: [PATCH 15/31] Add a couple more files to the core JS package Summary: Ref T5867. We have a bit more common JS now. Test Plan: Loaded some pages, saw fewer requests. Sanity-checked these resources against Multimeter in production. Reviewers: chad Reviewed By: chad Maniphest Tasks: T5867 Differential Revision: https://secure.phabricator.com/D17220 --- resources/celerity/map.php | 5 ++++- resources/celerity/packages.php | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index e97050fdbc..3ef94b5a78 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -10,7 +10,7 @@ return array( 'conpherence.pkg.css' => '0b64e988', 'conpherence.pkg.js' => '6249a1cf', 'core.pkg.css' => '85f51b68', - 'core.pkg.js' => '666970d7', + 'core.pkg.js' => 'f70cb91f', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '9535a7e6', 'differential.pkg.js' => 'ddfeb49b', @@ -2427,6 +2427,9 @@ return array( 'conpherence-thread-manager', 'javelin-behavior-detect-timezone', 'javelin-behavior-setup-check-https', + 'javelin-behavior-aphlict-status', + 'javelin-behavior-user-menu', + 'phabricator-favicon', ), 'darkconsole.pkg.js' => array( 'javelin-behavior-dark-console', diff --git a/resources/celerity/packages.php b/resources/celerity/packages.php index caa4512e34..288bd69ed2 100644 --- a/resources/celerity/packages.php +++ b/resources/celerity/packages.php @@ -84,6 +84,9 @@ return array( 'conpherence-thread-manager', 'javelin-behavior-detect-timezone', 'javelin-behavior-setup-check-https', + 'javelin-behavior-aphlict-status', + 'javelin-behavior-user-menu', + 'phabricator-favicon', ), 'core.pkg.css' => array( 'phabricator-core-css', From 545dad319ec04b39cd2ca2cf6f11cb51d633f20c Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 18 Jan 2017 09:37:42 -0800 Subject: [PATCH 16/31] Add an "Auditors" rule for Commits Summary: Fixes T5889. You can't write a rule like "if no other Herald rules did anything...", but you can use this rule to check for Owners or an explicit "Auditors" field doing things. Test Plan: Using the test console, ran an "Auditors" rule against a commit with and without an auditor. Got expected pass/fail outcomes. Reviewers: chad Reviewed By: chad Maniphest Tasks: T5889 Differential Revision: https://secure.phabricator.com/D17221 --- src/__phutil_library_map__.php | 2 + .../DiffusionCommitAuditorsHeraldField.php | 41 +++++++++++++++++++ .../PhabricatorRepositoryAuditRequest.php | 13 ++++++ 3 files changed, 56 insertions(+) create mode 100644 src/applications/diffusion/herald/DiffusionCommitAuditorsHeraldField.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 1e1ae93e85..7d5031e3dd 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -617,6 +617,7 @@ phutil_register_library_map(array( 'DiffusionCommitActionTransaction' => 'applications/diffusion/xaction/DiffusionCommitActionTransaction.php', 'DiffusionCommitAffectedFilesHeraldField' => 'applications/diffusion/herald/DiffusionCommitAffectedFilesHeraldField.php', 'DiffusionCommitAuditTransaction' => 'applications/diffusion/xaction/DiffusionCommitAuditTransaction.php', + 'DiffusionCommitAuditorsHeraldField' => 'applications/diffusion/herald/DiffusionCommitAuditorsHeraldField.php', 'DiffusionCommitAuditorsTransaction' => 'applications/diffusion/xaction/DiffusionCommitAuditorsTransaction.php', 'DiffusionCommitAuthorHeraldField' => 'applications/diffusion/herald/DiffusionCommitAuthorHeraldField.php', 'DiffusionCommitAutocloseHeraldField' => 'applications/diffusion/herald/DiffusionCommitAutocloseHeraldField.php', @@ -5321,6 +5322,7 @@ phutil_register_library_map(array( 'DiffusionCommitActionTransaction' => 'DiffusionCommitTransactionType', 'DiffusionCommitAffectedFilesHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitAuditTransaction' => 'DiffusionCommitActionTransaction', + 'DiffusionCommitAuditorsHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitAuditorsTransaction' => 'DiffusionCommitTransactionType', 'DiffusionCommitAuthorHeraldField' => 'DiffusionCommitHeraldField', 'DiffusionCommitAutocloseHeraldField' => 'DiffusionCommitHeraldField', diff --git a/src/applications/diffusion/herald/DiffusionCommitAuditorsHeraldField.php b/src/applications/diffusion/herald/DiffusionCommitAuditorsHeraldField.php new file mode 100644 index 0000000000..8deee3417e --- /dev/null +++ b/src/applications/diffusion/herald/DiffusionCommitAuditorsHeraldField.php @@ -0,0 +1,41 @@ +setViewer($viewer) + ->withPHIDs(array($object->getPHID())) + ->needAuditRequests(true) + ->executeOne(); + + $audits = $commit->getAudits(); + + $phids = array(); + foreach ($audits as $audit) { + if ($audit->isActiveAudit()) { + $phids[] = $audit->getAuditorPHID(); + } + } + + return $phids; + } + + protected function getHeraldFieldStandardType() { + return self::STANDARD_PHID_LIST; + } + + protected function getDatasource() { + return new DiffusionAuditorDatasource(); + } + +} diff --git a/src/applications/repository/storage/PhabricatorRepositoryAuditRequest.php b/src/applications/repository/storage/PhabricatorRepositoryAuditRequest.php index f0a17718aa..ea86594d9e 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryAuditRequest.php +++ b/src/applications/repository/storage/PhabricatorRepositoryAuditRequest.php @@ -49,6 +49,19 @@ final class PhabricatorRepositoryAuditRequest return $this->assertAttached($this->commit); } + public function isActiveAudit() { + switch ($this->getAuditStatus()) { + case PhabricatorAuditStatusConstants::NONE: + case PhabricatorAuditStatusConstants::AUDIT_NOT_REQUIRED: + case PhabricatorAuditStatusConstants::RESIGNED: + case PhabricatorAuditStatusConstants::CLOSED: + case PhabricatorAuditStatusConstants::CC: + return false; + } + + return true; + } + public function isInteresting() { switch ($this->getAuditStatus()) { case PhabricatorAuditStatusConstants::NONE: From 35f4514e3ff6d853699b82a0c46c6e62ebaae30e Mon Sep 17 00:00:00 2001 From: Chad Little Date: Wed, 18 Jan 2017 12:31:39 -0800 Subject: [PATCH 17/31] Fancier user menu Summary: Builds out more UI to reinforce just who you are in this world... A perfect person. Test Plan: Look at myself a lot. {F2435202} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17224 --- resources/celerity/map.php | 12 +++++----- .../PhabricatorHomeApplication.php | 20 ++++++++++++++-- src/view/layout/PhabricatorActionView.php | 2 +- .../css/application/base/main-menu-view.css | 23 +++++++++++++++++++ 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 3ef94b5a78..54898f5f77 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => '0b64e988', 'conpherence.pkg.js' => '6249a1cf', - 'core.pkg.css' => '85f51b68', + 'core.pkg.css' => 'e75e4f9d', 'core.pkg.js' => 'f70cb91f', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '9535a7e6', @@ -34,7 +34,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' => '7bc94bc2', + 'rsrc/css/application/base/main-menu-view.css' => '8eac4166', 'rsrc/css/application/base/notification-menu.css' => '6a697e43', 'rsrc/css/application/base/phabricator-application-launch-view.css' => '95351601', 'rsrc/css/application/base/phui-theme.css' => '798c69b8', @@ -798,7 +798,7 @@ return array( 'phabricator-flag-css' => 'bba8f811', 'phabricator-keyboard-shortcut' => '1ae869f2', 'phabricator-keyboard-shortcut-manager' => '4a021c10', - 'phabricator-main-menu-view' => '7bc94bc2', + 'phabricator-main-menu-view' => '8eac4166', 'phabricator-nav-view-css' => 'b29426e9', 'phabricator-notification' => 'ccf1cbf8', 'phabricator-notification-css' => '3f6c89c9', @@ -1502,9 +1502,6 @@ return array( 'owners-path-editor', 'javelin-behavior', ), - '7bc94bc2' => array( - 'phui-theme-css', - ), '7cbe244b' => array( 'javelin-install', 'javelin-util', @@ -1618,6 +1615,9 @@ return array( 'javelin-stratcom', 'javelin-util', ), + '8eac4166' => array( + 'phui-theme-css', + ), '8ff5e24c' => array( 'javelin-behavior', 'javelin-stratcom', diff --git a/src/applications/home/application/PhabricatorHomeApplication.php b/src/applications/home/application/PhabricatorHomeApplication.php index d3823dab85..20858e4931 100644 --- a/src/applications/home/application/PhabricatorHomeApplication.php +++ b/src/applications/home/application/PhabricatorHomeApplication.php @@ -86,14 +86,29 @@ final class PhabricatorHomeApplication extends PhabricatorApplication { PhabricatorUser $viewer, $application) { + $person_to_show = id(new PHUIObjectItemView()) + ->setObjectName($viewer->getRealName()) + ->setSubHead($viewer->getUsername()) + ->setImageURI($viewer->getProfileImageURI()); + + $user_view = id(new PHUIObjectItemListView()) + ->setViewer($viewer) + ->setFlush(true) + ->setSimple(true) + ->addItem($person_to_show) + ->addClass('phabricator-core-user-profile-object'); + $view = id(new PhabricatorActionListView()) ->setViewer($viewer); // User Menu $view->addAction( id(new PhabricatorActionView()) - ->setName($viewer->getRealName()) - ->setLabel(true)); + ->appendChild($user_view)); + + $view->addAction( + id(new PhabricatorActionView()) + ->setType(PhabricatorActionView::TYPE_DIVIDER)); $view->addAction( id(new PhabricatorActionView()) @@ -131,6 +146,7 @@ final class PhabricatorHomeApplication extends PhabricatorApplication { ->setName(pht('Log Out %s', $viewer->getUsername())) ->addSigil('logout-item') ->setHref('/logout/') + ->setColor(PhabricatorActionView::RED) ->setWorkflow(true)); return $view; diff --git a/src/view/layout/PhabricatorActionView.php b/src/view/layout/PhabricatorActionView.php index 74e3c0b12d..85b9d3abfe 100644 --- a/src/view/layout/PhabricatorActionView.php +++ b/src/view/layout/PhabricatorActionView.php @@ -284,7 +284,7 @@ final class PhabricatorActionView extends AphrontView { 'class' => 'phabricator-action-view-item', 'sigil' => $sigils, ), - array($icon, $this->name)); + array($icon, $this->name, $this->renderChildren())); } $classes = array(); diff --git a/webroot/rsrc/css/application/base/main-menu-view.css b/webroot/rsrc/css/application/base/main-menu-view.css index 2427ba4247..2bafa7f8f5 100644 --- a/webroot/rsrc/css/application/base/main-menu-view.css +++ b/webroot/rsrc/css/application/base/main-menu-view.css @@ -627,6 +627,29 @@ a.phabricator-core-user-menu .caret:before { margin: 3px 0 0 0; } +ul.phabricator-core-user-profile-object .phui-oi-objname { + font-size: {$biggestfontsize}; +} + +ul.phabricator-core-user-profile-object li.phui-oi, +ul.phabricator-core-user-profile-object .phui-oi-name, +ul.phabricator-core-user-profile-object .phui-oi-content, +ul.phabricator-core-user-profile-object .phui-oi-subhead { + padding: 0; + margin: 0; +} + +ul.phabricator-core-user-profile-object.phui-oi-list-simple .phui-oi-image { + height: 36px; + width: 36px; +} + +ul.phabricator-core-user-profile-object.phui-oi-list-simple + .phui-oi-content-box { + margin-left: 44px; +} + + /* - Print --------------------------------------------------------------------- */ From 90258ed491d559b620c9e42663d526ef3fa316b1 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 18 Jan 2017 11:29:38 -0800 Subject: [PATCH 18/31] Fix property shadowing on ActionListView after conversion to TagView Summary: See D17222. D17209 accidentally broke setting IDs on ActionListView by converting it into a TagView: TagView already has an `id` property, and this new `id` property on the subclass shadows it. Materially, the "Actions" mobile button in the headers of objects (for example: Maniphest Task -> shrink browser window -> click "Actions" next to task name) relies on setting IDs on list views. Test Plan: - Viewed a task. - Made browser window narrow. - Clicked `[= Actions]` button. - After patch: saw a dropdown menu. Reviewers: chad Reviewed By: chad Differential Revision: https://secure.phabricator.com/D17223 --- src/view/layout/PhabricatorActionListView.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/view/layout/PhabricatorActionListView.php b/src/view/layout/PhabricatorActionListView.php index 5ac28f81de..faf30555eb 100644 --- a/src/view/layout/PhabricatorActionListView.php +++ b/src/view/layout/PhabricatorActionListView.php @@ -4,7 +4,6 @@ final class PhabricatorActionListView extends AphrontTagView { private $actions = array(); private $object; - private $id = null; public function setObject(PhabricatorLiskDAO $object) { $this->object = $object; @@ -16,15 +15,6 @@ final class PhabricatorActionListView extends AphrontTagView { return $this; } - public function setID($id) { - $this->id = $id; - return $this; - } - - public function getID() { - return $this->id; - } - protected function getTagName() { return 'ul'; } From 45c3aaeb269eb04a3f2ab996448820701e15b51a Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 18 Jan 2017 11:17:11 -0800 Subject: [PATCH 19/31] Attempt to make dropdown item actions more consistent Summary: See D17210. Currently, this handler needs to be installed on each menu that doesn't build with the default behavior. Rather than copy-pasting it to the user menu, try to make it a default behavior. This adds a new rule: don't close the menu if the item is a dynamic item built in JS with PHUIXActionView. This allows dynamic items to control the menu themselves, while giving static items the desired default behavior. Test Plan: - Opened menus on: dashboards, user menu, timeline comments. Clicked stuff. Menus went away. - Other menus still seemed to work right: Diffusion, Favorites, mobile menu. Reviewers: chad Reviewed By: chad Differential Revision: https://secure.phabricator.com/D17222 --- resources/celerity/map.php | 72 +++++++++---------- .../projects/behavior-project-boards.js | 7 -- .../js/phui/behavior-phui-dropdown-menu.js | 14 ---- webroot/rsrc/js/phuix/PHUIXActionView.js | 2 + webroot/rsrc/js/phuix/PHUIXDropdownMenu.js | 28 ++++++++ 5 files changed, 66 insertions(+), 57 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 54898f5f77..ade2a4324c 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -10,7 +10,7 @@ return array( 'conpherence.pkg.css' => '0b64e988', 'conpherence.pkg.js' => '6249a1cf', 'core.pkg.css' => 'e75e4f9d', - 'core.pkg.js' => 'f70cb91f', + 'core.pkg.js' => '2291d3b2', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '9535a7e6', 'differential.pkg.js' => 'ddfeb49b', @@ -443,7 +443,7 @@ return array( 'rsrc/js/application/projects/WorkboardCard.js' => 'c587b80f', 'rsrc/js/application/projects/WorkboardColumn.js' => '21df4ff5', 'rsrc/js/application/projects/WorkboardController.js' => '55baf5ed', - 'rsrc/js/application/projects/behavior-project-boards.js' => '14a1faae', + 'rsrc/js/application/projects/behavior-project-boards.js' => '93ae974f', 'rsrc/js/application/projects/behavior-project-create.js' => '065227cc', 'rsrc/js/application/projects/behavior-reorder-columns.js' => 'e1d25dfb', 'rsrc/js/application/releeph/releeph-preview-branch.js' => 'b2b4fbaf', @@ -534,14 +534,14 @@ return array( 'rsrc/js/core/behavior-watch-anchor.js' => '9f36c42d', 'rsrc/js/core/behavior-workflow.js' => '0a3f3021', 'rsrc/js/core/phtize.js' => 'd254d646', - 'rsrc/js/phui/behavior-phui-dropdown-menu.js' => '8744dfd1', + 'rsrc/js/phui/behavior-phui-dropdown-menu.js' => 'b95d6f7d', 'rsrc/js/phui/behavior-phui-file-upload.js' => 'b003d4fb', 'rsrc/js/phui/behavior-phui-submenu.js' => 'a6f7a73b', 'rsrc/js/phui/behavior-phui-tab-group.js' => '0a0b10e9', 'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8', - 'rsrc/js/phuix/PHUIXActionView.js' => '9cc178ed', + 'rsrc/js/phuix/PHUIXActionView.js' => 'b3465b9b', 'rsrc/js/phuix/PHUIXAutocomplete.js' => '6d86ce8b', - 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '82e270da', + 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '8018ee50', 'rsrc/js/phuix/PHUIXFormControl.js' => 'bbece68d', 'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b', ), @@ -687,14 +687,14 @@ return array( 'javelin-behavior-phabricator-watch-anchor' => '9f36c42d', 'javelin-behavior-pholio-mock-edit' => 'bee502c8', 'javelin-behavior-pholio-mock-view' => 'fbe497e7', - 'javelin-behavior-phui-dropdown-menu' => '8744dfd1', + 'javelin-behavior-phui-dropdown-menu' => 'b95d6f7d', 'javelin-behavior-phui-file-upload' => 'b003d4fb', 'javelin-behavior-phui-hovercards' => 'bcaccd64', 'javelin-behavior-phui-submenu' => 'a6f7a73b', 'javelin-behavior-phui-tab-group' => '0a0b10e9', 'javelin-behavior-policy-control' => 'd0c516d5', 'javelin-behavior-policy-rule-editor' => '5e9f347c', - 'javelin-behavior-project-boards' => '14a1faae', + 'javelin-behavior-project-boards' => '93ae974f', 'javelin-behavior-project-create' => '065227cc', 'javelin-behavior-quicksand-blacklist' => '7927a7d3', 'javelin-behavior-read-only-warning' => 'ba158207', @@ -898,9 +898,9 @@ return array( 'phui-workcard-view-css' => 'cca5fa92', 'phui-workpanel-view-css' => 'a3a63478', 'phuix-action-list-view' => 'b5c256b8', - 'phuix-action-view' => '9cc178ed', + 'phuix-action-view' => 'b3465b9b', 'phuix-autocomplete' => '6d86ce8b', - 'phuix-dropdown-menu' => '82e270da', + 'phuix-dropdown-menu' => '8018ee50', 'phuix-form-control-view' => 'bbece68d', 'phuix-icon-view' => 'bff6884b', 'policy-css' => '957ea14c', @@ -1044,15 +1044,6 @@ return array( 'javelin-dom', 'javelin-history', ), - '14a1faae' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-util', - 'javelin-vector', - 'javelin-stratcom', - 'javelin-workflow', - 'javelin-workboard-controller', - ), '185bbd53' => array( 'javelin-install', ), @@ -1519,6 +1510,13 @@ return array( 'javelin-behavior', 'javelin-history', ), + '8018ee50' => array( + 'javelin-install', + 'javelin-util', + 'javelin-dom', + 'javelin-vector', + 'javelin-stratcom', + ), '805b806a' => array( 'javelin-magical-init', 'javelin-install', @@ -1526,13 +1524,6 @@ return array( 'javelin-vector', 'javelin-stratcom', ), - '82e270da' => array( - 'javelin-install', - 'javelin-util', - 'javelin-dom', - 'javelin-vector', - 'javelin-stratcom', - ), '834a1173' => array( 'javelin-behavior', 'javelin-scrollbar', @@ -1561,12 +1552,6 @@ return array( 'phabricator-tooltip', 'changeset-view-manager', ), - '8744dfd1' => array( - 'javelin-behavior', - 'javelin-stratcom', - 'javelin-dom', - 'phuix-dropdown-menu', - ), '88236f00' => array( 'javelin-behavior', 'phabricator-keyboard-shortcut', @@ -1639,6 +1624,15 @@ return array( 'javelin-stratcom', 'javelin-dom', ), + '93ae974f' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-util', + 'javelin-vector', + 'javelin-stratcom', + 'javelin-workflow', + 'javelin-workboard-controller', + ), '93d0c9e3' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1699,11 +1693,6 @@ return array( 'javelin-workflow', 'javelin-stratcom', ), - '9cc178ed' => array( - 'javelin-install', - 'javelin-dom', - 'javelin-util', - ), '9d9685d6' => array( 'phui-oi-list-view-css', ), @@ -1849,6 +1838,11 @@ return array( 'javelin-uri', 'javelin-request', ), + 'b3465b9b' => array( + 'javelin-install', + 'javelin-dom', + 'javelin-util', + ), 'b3a4b884' => array( 'javelin-behavior', 'phabricator-prefab', @@ -1901,6 +1895,12 @@ return array( 'javelin-json', 'phabricator-draggable-list', ), + 'b95d6f7d' => array( + 'javelin-behavior', + 'javelin-stratcom', + 'javelin-dom', + 'phuix-dropdown-menu', + ), 'ba158207' => array( 'javelin-behavior', 'javelin-uri', diff --git a/webroot/rsrc/js/application/projects/behavior-project-boards.js b/webroot/rsrc/js/application/projects/behavior-project-boards.js index 8fccb1dc91..85f41d7907 100644 --- a/webroot/rsrc/js/application/projects/behavior-project-boards.js +++ b/webroot/rsrc/js/application/projects/behavior-project-boards.js @@ -34,13 +34,6 @@ JX.behavior('project-boards', function(config, statics) { data.menu = new JX.PHUIXDropdownMenu(button); data.menu.setContent(list); data.menu.open(); - - JX.DOM.listen(list, 'click', 'tag:a', function(e) { - if (!e.isNormalClick()) { - return; - } - data.menu.close(); - }); }); JX.Stratcom.listen( diff --git a/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js b/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js index 8c3c9cc09f..d2fddc8e70 100644 --- a/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js +++ b/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js @@ -42,20 +42,6 @@ JX.behavior('phui-dropdown-menu', function() { }); data.menu.open(); - - JX.DOM.listen(list, 'click', 'tag:a', function(e) { - if (!e.isNormalClick()) { - return; - } - - // If this item opens a submenu, we don't want to close the current - // menu. One submenu is "Edit Related Objects..." on mobile. - if (JX.Stratcom.hasSigil(e.getTarget(), 'keep-open')) { - return; - } - - data.menu.close(); - }); }); }); diff --git a/webroot/rsrc/js/phuix/PHUIXActionView.js b/webroot/rsrc/js/phuix/PHUIXActionView.js index 999f80dc4b..d5d849e733 100644 --- a/webroot/rsrc/js/phuix/PHUIXActionView.js +++ b/webroot/rsrc/js/phuix/PHUIXActionView.js @@ -96,6 +96,8 @@ JX.install('PHUIXActionView', { className: classes.join(' ') }; this._node = JX.$N('li', attr, content); + + JX.Stratcom.addSigil(this._node, 'phuix-action-view'); } return this._node; diff --git a/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js b/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js index d9fd1877b8..3f93c1ee41 100644 --- a/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js +++ b/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js @@ -40,6 +40,12 @@ JX.install('PHUIXDropdownMenu', { JX.Stratcom.listen('phuix.dropdown.open', null, JX.bind(this, this.close)); JX.Stratcom.listen('keydown', null, JX.bind(this, this._onkey)); + + JX.DOM.listen( + this._getMenuNode(), + 'click', + 'tag:a', + JX.bind(this, this._onlink)); }, events: ['open', 'close'], @@ -112,6 +118,28 @@ JX.install('PHUIXDropdownMenu', { e.prevent(); }, + _onlink: function(e) { + if (!e.isNormalClick()) { + return; + } + + // If this action was built dynamically with PHUIXActionView, don't + // do anything by default. The caller is repsonsible for installing a + // handler if they want to react to clicks. + if (e.getNode('phuix-action-view')) { + return; + } + + // If this item opens a submenu, we don't want to close the current + // menu. One submenu is "Edit Related Objects..." on mobile. + var link = e.getNode('tag:a'); + if (JX.Stratcom.hasSigil(link, 'keep-open')) { + return; + } + + this.close(); + }, + _onanyclick : function(e) { if (!this._open) { return; From b8e04fe0419d1d4bdfc64ee964ed48fc34a4b5a1 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 18 Jan 2017 12:01:38 -0800 Subject: [PATCH 20/31] Improve handle batching behavior for commit list view Summary: Ref T10978. Handle loads can be batched a bit more efficiently by doing them upfront. Test Plan: Queries dropped a bit locally, but I mostly have the same autors/auditors. I'm seeing 286 queries on my account in production, so I'll check what happens with that. Reviewers: chad Reviewed By: chad Maniphest Tasks: T10978 Differential Revision: https://secure.phabricator.com/D17225 --- .../audit/view/PhabricatorAuditListView.php | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/applications/audit/view/PhabricatorAuditListView.php b/src/applications/audit/view/PhabricatorAuditListView.php index 8d4aef61f2..4afb069778 100644 --- a/src/applications/audit/view/PhabricatorAuditListView.php +++ b/src/applications/audit/view/PhabricatorAuditListView.php @@ -83,7 +83,21 @@ final class PhabricatorAuditListView extends AphrontView { $viewer = $this->getViewer(); $rowc = array(); - $handles = $viewer->loadHandles(mpull($this->commits, 'getPHID')); + $phids = array(); + foreach ($this->getCommits() as $commit) { + $phids[] = $commit->getPHID(); + + foreach ($commit->getAudits() as $audit) { + $phids[] = $audit->getAuditorPHID(); + } + + $author_phid = $commit->getAuthorPHID(); + if ($author_phid) { + $phids[] = $author_phid; + } + } + + $handles = $viewer->loadHandles($phids); $show_drafts = $this->getShowDrafts(); @@ -106,14 +120,6 @@ final class PhabricatorAuditListView extends AphrontView { $commit_desc = $this->getCommitDescription($commit_phid); $committed = phabricator_datetime($commit->getEpoch(), $viewer); - $audits = mpull($commit->getAudits(), null, 'getAuditorPHID'); - $auditors = array(); - foreach ($audits as $audit) { - $auditor_phid = $audit->getAuditorPHID(); - $auditors[$auditor_phid] = $viewer->renderHandle($auditor_phid); - } - $auditors = phutil_implode_html(', ', $auditors); - $status = $commit->getAuditStatus(); $status_text = @@ -125,7 +131,7 @@ final class PhabricatorAuditListView extends AphrontView { $author_phid = $commit->getAuthorPHID(); if ($author_phid) { - $author_name = $viewer->renderHandle($author_phid); + $author_name = $handles[$author_phid]->renderLink(); } else { $author_name = $commit->getCommitData()->getAuthorName(); } @@ -145,8 +151,15 @@ final class PhabricatorAuditListView extends AphrontView { ->addAttribute(pht('Author: %s', $author_name)) ->addIcon('none', $committed); - if (!empty($auditors)) { - $item->addByLine(pht('Auditors: %s', $auditors)); + $audits = $commit->getAudits(); + $auditor_phids = mpull($audits, 'getAuditorPHID'); + if ($auditor_phids) { + $item->addByLine( + array( + pht('Auditors:'), + ' ', + $handles->newSublist($auditor_phids)->renderList(), + )); } if ($status_color) { From 269dd81f91784d40abdd9af2d95061cdb3d2c394 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 18 Jan 2017 12:56:49 -0800 Subject: [PATCH 21/31] Allow users to re-accept or re-reject a revision if they have authority over package/project reviewers not yet in the target state Summary: To set this up: - alice accepts a revision. - Something adds a package or project she has authority over as a reviewer. - Because alice has already accepted, she can not re-accept, but she should be able to (in order to accept on behalf of the new project or package). Test Plan: - Created a revision. - Accepted as user "dog". - Added "dog project". - Re-accepted. - Could not three-accept. - Removed "dog project. - Rejected. - Added "dog project". - Re-rejected. - Could not three-reject. Reviewers: chad, eadler Reviewed By: chad, eadler Differential Revision: https://secure.phabricator.com/D17226 --- .../DifferentialRevisionAcceptTransaction.php | 4 +-- .../DifferentialRevisionRejectTransaction.php | 4 +-- .../DifferentialRevisionReviewTransaction.php | 28 +++++++++++++++---- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/applications/differential/xaction/DifferentialRevisionAcceptTransaction.php b/src/applications/differential/xaction/DifferentialRevisionAcceptTransaction.php index df4e3b4d33..3a64a44767 100644 --- a/src/applications/differential/xaction/DifferentialRevisionAcceptTransaction.php +++ b/src/applications/differential/xaction/DifferentialRevisionAcceptTransaction.php @@ -50,7 +50,7 @@ final class DifferentialRevisionAcceptTransaction public function generateOldValue($object) { $actor = $this->getActor(); - return $this->isViewerAcceptingReviewer($object, $actor); + return $this->isViewerFullyAccepted($object, $actor); } public function applyExternalEffects($object, $value) { @@ -79,7 +79,7 @@ final class DifferentialRevisionAcceptTransaction } } - if ($this->isViewerAcceptingReviewer($object, $viewer)) { + if ($this->isViewerFullyAccepted($object, $viewer)) { throw new Exception( pht( 'You can not accept this revision because you have already '. diff --git a/src/applications/differential/xaction/DifferentialRevisionRejectTransaction.php b/src/applications/differential/xaction/DifferentialRevisionRejectTransaction.php index 96812de06b..b4c71209aa 100644 --- a/src/applications/differential/xaction/DifferentialRevisionRejectTransaction.php +++ b/src/applications/differential/xaction/DifferentialRevisionRejectTransaction.php @@ -46,7 +46,7 @@ final class DifferentialRevisionRejectTransaction public function generateOldValue($object) { $actor = $this->getActor(); - return $this->isViewerRejectingReviewer($object, $actor); + return $this->isViewerFullyRejected($object, $actor); } public function applyExternalEffects($object, $value) { @@ -72,7 +72,7 @@ final class DifferentialRevisionRejectTransaction 'not own.')); } - if ($this->isViewerRejectingReviewer($object, $viewer)) { + if ($this->isViewerFullyRejected($object, $viewer)) { throw new Exception( pht( 'You can not request changes to this revision because you have '. diff --git a/src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php b/src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php index de75977220..7e0c60a7b1 100644 --- a/src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php +++ b/src/applications/differential/xaction/DifferentialRevisionReviewTransaction.php @@ -13,10 +13,10 @@ abstract class DifferentialRevisionReviewTransaction return ($this->getViewerReviewerStatus($revision, $viewer) !== null); } - protected function isViewerAcceptingReviewer( + protected function isViewerFullyAccepted( DifferentialRevision $revision, PhabricatorUser $viewer) { - return $this->isViewerReviewerStatusAmong( + return $this->isViewerReviewerStatusFullyAmong( $revision, $viewer, array( @@ -24,10 +24,10 @@ abstract class DifferentialRevisionReviewTransaction )); } - protected function isViewerRejectingReviewer( + protected function isViewerFullyRejected( DifferentialRevision $revision, PhabricatorUser $viewer) { - return $this->isViewerReviewerStatusAmong( + return $this->isViewerReviewerStatusFullyAmong( $revision, $viewer, array( @@ -54,18 +54,34 @@ abstract class DifferentialRevisionReviewTransaction return null; } - protected function isViewerReviewerStatusAmong( + protected function isViewerReviewerStatusFullyAmong( DifferentialRevision $revision, PhabricatorUser $viewer, array $status_list) { + // If the user themselves is not a reviewer, the reviews they have + // authority over can not all be in any set of states since their own + // personal review has no state. $status = $this->getViewerReviewerStatus($revision, $viewer); if ($status === null) { return false; } + // Otherwise, check that all reviews they have authority over are in + // the desired set of states. $status_map = array_fuse($status_list); - return isset($status_map[$status]); + foreach ($revision->getReviewerStatus() as $reviewer) { + if (!$reviewer->hasAuthority($viewer)) { + continue; + } + + $status = $reviewer->getStatus(); + if (!isset($status_map[$status])) { + return false; + } + } + + return true; } protected function applyReviewerEffect( From b0dfd42eef292a2727d8b791210b7ab33026e04d Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 19 Jan 2017 11:06:42 -0800 Subject: [PATCH 22/31] Don't require edit capability on the Favorites application to edit personal menu items Summary: Ref T11096. Currently, editing ProfileMenuItemConfigurations always requires that you can edit the corresponding object. This is correct for global items (for example: you can't change the global menu for a project unless you can edit the project) but not for personal items. For personal items, only require that the user can edit the `customPHID` object. Today, this is always their own profile. Test Plan: As a non-admin, edited personal menu items. Reviewers: chad Reviewed By: chad Maniphest Tasks: T11096 Differential Revision: https://secure.phabricator.com/D17228 --- .../engine/PhabricatorProfileMenuEngine.php | 14 ++++++++++---- .../PhabricatorProfileMenuItemConfiguration.php | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/applications/search/engine/PhabricatorProfileMenuEngine.php b/src/applications/search/engine/PhabricatorProfileMenuEngine.php index 6157d5f657..3e11436ced 100644 --- a/src/applications/search/engine/PhabricatorProfileMenuEngine.php +++ b/src/applications/search/engine/PhabricatorProfileMenuEngine.php @@ -557,10 +557,16 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { $first_item->willBuildNavigationItems($group); } - PhabricatorPolicyFilter::requireCapability( - $viewer, - $object, - PhabricatorPolicyCapability::CAN_EDIT); + // Users only need to be able to edit the object which this menu appears + // on if they're editing global menu items. For example, users do not need + // to be able to edit the Favorites application to add new items to the + // Favorites menu. + if (!$this->getCustomPHID()) { + PhabricatorPolicyFilter::requireCapability( + $viewer, + $object, + PhabricatorPolicyCapability::CAN_EDIT); + } $list_id = celerity_generate_unique_node_id(); diff --git a/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php b/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php index 943474669d..e1571ee6f6 100644 --- a/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php +++ b/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php @@ -189,6 +189,21 @@ final class PhabricatorProfileMenuItemConfiguration public function getExtendedPolicy($capability, PhabricatorUser $viewer) { + // If this is an item with a custom PHID (like a personal menu item), + // we only require that the user can edit the corresponding custom + // object (usually their own user profile), not the object that the + // menu appears on (which may be an Application like Favorites or Home). + if ($capability == PhabricatorPolicyCapability::CAN_EDIT) { + if ($this->getCustomPHID()) { + return array( + array( + $this->getCustomPHID(), + $capability, + ), + ); + } + } + return array( array( $this->getProfileObject(), From a9158d34d46abf1cb76ec21b30a7176b68b46fc1 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 19 Jan 2017 10:39:05 -0800 Subject: [PATCH 23/31] Show commit audit status in repository history tables, including merge commit lists Summary: Fixes T6024. Ref T12121. Currently, we show build status in commit history tables; show audit status alongside it. Also: - Change the "Author/Committer" header to just "Author"; I think it's reasonably obvious what "x/y" means (if you can't guess, you can click the commit and likely figure it out) and this gives us a little more space. - Make the audit list look more like the corresponding list in Differential, with similar formatting. Test Plan: - Viewed history of a repostiory, saw audit status. - Viewed a merge commit, saw audit status in the list of merged commits. - Viewed a commit search results list. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12121, T6024 Differential Revision: https://secure.phabricator.com/D17227 --- .../audit/view/PhabricatorAuditListView.php | 20 +++++++++---------- .../view/DiffusionHistoryTableView.php | 20 ++++++++++++++++++- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/applications/audit/view/PhabricatorAuditListView.php b/src/applications/audit/view/PhabricatorAuditListView.php index 4afb069778..9207230e7c 100644 --- a/src/applications/audit/view/PhabricatorAuditListView.php +++ b/src/applications/audit/view/PhabricatorAuditListView.php @@ -139,7 +139,9 @@ final class PhabricatorAuditListView extends AphrontView { $item = id(new PHUIObjectItemView()) ->setObjectName($commit_name) ->setHeader($commit_desc) - ->setHref($commit_link); + ->setHref($commit_link) + ->addByline(pht('Author: %s', $author_name)) + ->addIcon('none', $committed); if ($show_drafts) { if ($commit->getHasDraft($viewer)) { @@ -147,20 +149,16 @@ final class PhabricatorAuditListView extends AphrontView { } } - $item - ->addAttribute(pht('Author: %s', $author_name)) - ->addIcon('none', $committed); - $audits = $commit->getAudits(); $auditor_phids = mpull($audits, 'getAuditorPHID'); if ($auditor_phids) { - $item->addByLine( - array( - pht('Auditors:'), - ' ', - $handles->newSublist($auditor_phids)->renderList(), - )); + $auditor_list = $handles->newSublist($auditor_phids) + ->renderList() + ->setAsInline(true); + } else { + $auditor_list = phutil_tag('em', array(), pht('None')); } + $item->addAttribute(pht('Auditors: %s', $auditor_list)); if ($status_color) { $item->setStatusIcon($status_icon.' '.$status_color, $status_text); diff --git a/src/applications/diffusion/view/DiffusionHistoryTableView.php b/src/applications/diffusion/view/DiffusionHistoryTableView.php index 4c19e3762b..bb3aee37da 100644 --- a/src/applications/diffusion/view/DiffusionHistoryTableView.php +++ b/src/applications/diffusion/view/DiffusionHistoryTableView.php @@ -187,6 +187,19 @@ final class DiffusionHistoryTableView extends DiffusionView { 'type' => $history->getFileType(), )); + $status = $commit->getAuditStatus(); + $icon = PhabricatorAuditCommitStatusConstants::getStatusIcon($status); + $color = PhabricatorAuditCommitStatusConstants::getStatusColor($status); + $name = PhabricatorAuditCommitStatusConstants::getStatusName($status); + + $audit_view = id(new PHUIIconView()) + ->setIcon($icon, $color) + ->addSigil('has-tooltip') + ->setMetadata( + array( + 'tip' => $name, + )); + $rows[] = array( $graph ? $graph[$ii++] : null, $browse, @@ -194,6 +207,7 @@ final class DiffusionHistoryTableView extends DiffusionView { $drequest->getRepository(), $history->getCommitIdentifier()), $build, + $audit_view, ($commit ? self::linkRevision(idx($this->revisions, $commit->getPHID())) : null), @@ -211,7 +225,8 @@ final class DiffusionHistoryTableView extends DiffusionView { pht('Commit'), null, null, - pht('Author/Committer'), + null, + pht('Author'), pht('Details'), pht('Committed'), )); @@ -221,6 +236,7 @@ final class DiffusionHistoryTableView extends DiffusionView { 'nudgeright', '', 'icon', + 'icon', '', '', 'wide', @@ -232,6 +248,7 @@ final class DiffusionHistoryTableView extends DiffusionView { true, true, $has_any_build, + true, $show_revisions, )); $view->setDeviceVisibility( @@ -241,6 +258,7 @@ final class DiffusionHistoryTableView extends DiffusionView { true, true, true, + true, false, true, false, From f8cebdc418e8702921ec0d3b3c8e4ce66689609f Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 19 Jan 2017 11:50:37 -0800 Subject: [PATCH 24/31] Make Differential inline events actually trigger comment preview refreshes Summary: Earlier, I made some changes so that when you create or edit an inline, the comment at the bottom of the page updates (even though you didn't fiddle with the stacked actions inputs). At the last second I broke them by spelling this wrong while cleaning things up, so they didn't actually work. Spell the property correctly ("showPreview", not "shouldPreview"). Also, we have some JS which rewrites "Not Visible" into "View", but it fires in an inconvenient way now and is flickery for me. Ideally this should get cleaned up slightly better eventualy, but at least make is stop doing so much flickery layout for now. Test Plan: - Wrote no comment on a revision. - Added an inline. - Saw comment preview properly update immediately. Reviewers: chad Reviewed By: chad Differential Revision: https://secure.phabricator.com/D17229 --- resources/celerity/map.php | 22 +++++++++---------- .../view/PHUIDiffInlineCommentDetailView.php | 2 +- .../transactions/behavior-comment-actions.js | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index ade2a4324c..8649bdf11b 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -453,7 +453,7 @@ return array( 'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e2e0a072', 'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08', 'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f', - 'rsrc/js/application/transactions/behavior-comment-actions.js' => 'b52947eb', + 'rsrc/js/application/transactions/behavior-comment-actions.js' => '9a6dd75c', 'rsrc/js/application/transactions/behavior-reorder-configs.js' => 'd7a74243', 'rsrc/js/application/transactions/behavior-reorder-fields.js' => 'b59e1e96', 'rsrc/js/application/transactions/behavior-show-older-transactions.js' => '94c65b72', @@ -609,7 +609,7 @@ return array( 'javelin-behavior-bulk-job-reload' => 'edf8a145', 'javelin-behavior-calendar-month-view' => 'fe33e256', 'javelin-behavior-choose-control' => '327a00d1', - 'javelin-behavior-comment-actions' => 'b52947eb', + 'javelin-behavior-comment-actions' => '9a6dd75c', 'javelin-behavior-config-reorder-fields' => 'b6993408', 'javelin-behavior-conpherence-menu' => '7524fcfa', 'javelin-behavior-conpherence-participant-pane' => '8604caa8', @@ -1682,6 +1682,15 @@ return array( 'phabricator-phtize', 'changeset-view-manager', ), + '9a6dd75c' => array( + 'javelin-behavior', + 'javelin-stratcom', + 'javelin-workflow', + 'javelin-dom', + 'phuix-form-control-view', + 'phuix-icon-view', + 'javelin-behavior-phabricator-gesture', + ), '9a8cb501' => array( 'aphront-typeahead-control-css', 'phui-tag-view-css', @@ -1856,15 +1865,6 @@ return array( 'javelin-typeahead-preloaded-source', 'javelin-util', ), - 'b52947eb' => array( - 'javelin-behavior', - 'javelin-stratcom', - 'javelin-workflow', - 'javelin-dom', - 'phuix-form-control-view', - 'phuix-icon-view', - 'javelin-behavior-phabricator-gesture', - ), 'b59e1e96' => array( 'javelin-behavior', 'javelin-stratcom', diff --git a/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php b/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php index 808fb5d067..f01bfbdb65 100644 --- a/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php +++ b/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php @@ -270,7 +270,7 @@ final class PHUIDiffInlineCommentDetailView ), 'sigil' => 'differential-inline-preview-jump', ), - pht('Not Visible')); + pht('View')); $action_buttons[] = id(new PHUIButtonView()) ->setTag('a') diff --git a/webroot/rsrc/js/application/transactions/behavior-comment-actions.js b/webroot/rsrc/js/application/transactions/behavior-comment-actions.js index 44d5597cb5..11141f138a 100644 --- a/webroot/rsrc/js/application/transactions/behavior-comment-actions.js +++ b/webroot/rsrc/js/application/transactions/behavior-comment-actions.js @@ -126,7 +126,7 @@ JX.behavior('comment-actions', function(config) { } function force_preview() { - if (!config.shouldPreview) { + if (!config.showPreview) { return; } From 1bcc8a3d98e00ab4b8c260038d4f2e6f51174fb0 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 19 Jan 2017 12:51:54 -0800 Subject: [PATCH 25/31] Remove timeline from Profile Manage Summary: Not sure this page is really providing any value, the timeline always says "edited this object" and there is a list of actions. Seems we could move actions back to the profile proper, but they feel very... engineery to me. Or we could fix the timeline stories, but my guess is they aren't useful or we would have gotten such feedback. Test Plan: Review manage page, timeline is gone. Page is clean. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17230 --- .../PhabricatorPeopleProfileManageController.php | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/applications/people/controller/PhabricatorPeopleProfileManageController.php b/src/applications/people/controller/PhabricatorPeopleProfileManageController.php index c5a3ceabd4..ba533c041c 100644 --- a/src/applications/people/controller/PhabricatorPeopleProfileManageController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfileManageController.php @@ -45,11 +45,6 @@ final class PhabricatorPeopleProfileManageController $nav = $this->getProfileMenu(); $nav->selectFilter(PhabricatorPeopleProfileMenuEngine::ITEM_MANAGE); - $timeline = $this->buildTransactionTimeline( - $user, - new PhabricatorPeopleTransactionQuery()); - $timeline->setShouldTerminate(true); - $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Manage')); $crumbs->setBorder(true); @@ -57,11 +52,7 @@ final class PhabricatorPeopleProfileManageController $manage = id(new PHUITwoColumnView()) ->setHeader($header) ->setCurtain($curtain) - ->addPropertySection(pht('Details'), $properties) - ->setMainColumn( - array( - $timeline, - )); + ->addPropertySection(pht('Details'), $properties); return $this->newPage() ->setTitle( From 14dfff9c99d23c118b573b58dbaef4dad59ebab5 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 19 Jan 2017 13:23:42 -0800 Subject: [PATCH 26/31] Mark fields as required on MenuItems Summary: Mark required fields as required. Though in testing, none of these work. Test Plan: Try to save a form without an app/project/dashboard and see success (not expected) Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17231 --- .../search/menuitem/PhabricatorApplicationProfileMenuItem.php | 1 + .../search/menuitem/PhabricatorDashboardProfileMenuItem.php | 1 + .../search/menuitem/PhabricatorEditEngineProfileMenuItem.php | 1 + .../search/menuitem/PhabricatorProjectProfileMenuItem.php | 1 + 4 files changed, 4 insertions(+) diff --git a/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php index 214819100e..a207f57f3a 100644 --- a/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php @@ -34,6 +34,7 @@ final class PhabricatorApplicationProfileMenuItem id(new PhabricatorDatasourceEditField()) ->setKey('application') ->setLabel(pht('Application')) + ->setIsRequired(true) ->setDatasource(new PhabricatorApplicationDatasource()) ->setSingleValue($config->getMenuItemProperty('application')), ); diff --git a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php index 9074b1b117..9b9d1dff7c 100644 --- a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php @@ -77,6 +77,7 @@ final class PhabricatorDashboardProfileMenuItem id(new PhabricatorDatasourceEditField()) ->setKey('dashboardPHID') ->setLabel(pht('Dashboard')) + ->setIsRequired(true) ->setDatasource(new PhabricatorDashboardDatasource()) ->setSingleValue($config->getMenuItemProperty('dashboardPHID')), ); diff --git a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php index 374fe10366..071efa80dd 100644 --- a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php @@ -85,6 +85,7 @@ final class PhabricatorEditEngineProfileMenuItem id(new PhabricatorDatasourceEditField()) ->setKey('formKey') ->setLabel(pht('Form')) + ->setIsRequired(true) ->setDatasource(new PhabricatorEditEngineDatasource()) ->setSingleValue($config->getMenuItemProperty('formKey')), ); diff --git a/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php index 002a3fcace..e47d97677f 100644 --- a/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php @@ -78,6 +78,7 @@ final class PhabricatorProjectProfileMenuItem id(new PhabricatorDatasourceEditField()) ->setKey('project') ->setLabel(pht('Project')) + ->setIsRequired(true) ->setDatasource(new PhabricatorProjectDatasource()) ->setSingleValue($config->getMenuItemProperty('project')), ); From 58c857a6816d44687b12a51a86331e52c7a20005 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 19 Jan 2017 14:44:04 -0800 Subject: [PATCH 27/31] Remove motivator panel Summary: Removes the often funny, but never really used but will cause us bug reports someday.... cat facts. Test Plan: Install cat facts, run storage upgrade, see no cat facts in menu. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12126 Differential Revision: https://secure.phabricator.com/D17233 --- .../20170119.menuitem.motivator.01.php | 9 + src/__phutil_library_map__.php | 2 - .../PhabricatorMotivatorProfileMenuItem.php | 164 ------------------ 3 files changed, 9 insertions(+), 166 deletions(-) create mode 100644 resources/sql/autopatches/20170119.menuitem.motivator.01.php delete mode 100644 src/applications/search/menuitem/PhabricatorMotivatorProfileMenuItem.php diff --git a/resources/sql/autopatches/20170119.menuitem.motivator.01.php b/resources/sql/autopatches/20170119.menuitem.motivator.01.php new file mode 100644 index 0000000000..16a16fe530 --- /dev/null +++ b/resources/sql/autopatches/20170119.menuitem.motivator.01.php @@ -0,0 +1,9 @@ +establishConnection('w'); + +queryfx( + $conn_w, + 'DELETE FROM %T WHERE menuItemKey = "motivator"', + $table->getTableName()); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 7d5031e3dd..c828c6b04e 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3020,7 +3020,6 @@ phutil_register_library_map(array( 'PhabricatorModularTransactionType' => 'applications/transactions/storage/PhabricatorModularTransactionType.php', 'PhabricatorMonospacedFontSetting' => 'applications/settings/setting/PhabricatorMonospacedFontSetting.php', 'PhabricatorMonospacedTextareasSetting' => 'applications/settings/setting/PhabricatorMonospacedTextareasSetting.php', - 'PhabricatorMotivatorProfileMenuItem' => 'applications/search/menuitem/PhabricatorMotivatorProfileMenuItem.php', 'PhabricatorMultiColumnUIExample' => 'applications/uiexample/examples/PhabricatorMultiColumnUIExample.php', 'PhabricatorMultiFactorSettingsPanel' => 'applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php', 'PhabricatorMultimeterApplication' => 'applications/multimeter/application/PhabricatorMultimeterApplication.php', @@ -8081,7 +8080,6 @@ phutil_register_library_map(array( 'PhabricatorModularTransactionType' => 'Phobject', 'PhabricatorMonospacedFontSetting' => 'PhabricatorStringSetting', 'PhabricatorMonospacedTextareasSetting' => 'PhabricatorSelectSetting', - 'PhabricatorMotivatorProfileMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorMultiColumnUIExample' => 'PhabricatorUIExample', 'PhabricatorMultiFactorSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorMultimeterApplication' => 'PhabricatorApplication', diff --git a/src/applications/search/menuitem/PhabricatorMotivatorProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorMotivatorProfileMenuItem.php deleted file mode 100644 index f53bc2b0eb..0000000000 --- a/src/applications/search/menuitem/PhabricatorMotivatorProfileMenuItem.php +++ /dev/null @@ -1,164 +0,0 @@ -getOptions(); - $name = idx($options, $config->getMenuItemProperty('source')); - if ($name !== null) { - return pht('Motivator: %s', $name); - } else { - return pht('Motivator'); - } - } - - public function buildEditEngineFields( - PhabricatorProfileMenuItemConfiguration $config) { - return array( - id(new PhabricatorInstructionsEditField()) - ->setValue( - pht( - 'Motivate your team with inspirational quotes from great minds. '. - 'This menu item shows a new quote every day.')), - id(new PhabricatorSelectEditField()) - ->setKey('source') - ->setLabel(pht('Source')) - ->setOptions($this->getOptions()), - ); - } - - private function getOptions() { - return array( - 'catfacts' => pht('Cat Facts'), - ); - } - - protected function newNavigationMenuItems( - PhabricatorProfileMenuItemConfiguration $config) { - - $source = $config->getMenuItemProperty('source'); - - switch ($source) { - case 'catfacts': - default: - $facts = $this->getCatFacts(); - break; - } - - $fact = $this->selectFact($facts); - - switch ($source) { - case 'catfacts': - default: - $fact = array( - id(new PHUIIconView())->setIcon('fa-paw'), - ' ', - $fact, - ); - break; - } - - $fact = phutil_tag( - 'div', - array( - 'class' => 'phui-motivator', - ), - $fact); - - $item = $this->newItem() - ->appendChild($fact); - - return array( - $item, - ); - } - - private function getCatFacts() { - return array( - pht('Cats purr when they are happy, upset, or asleep.'), - pht('The first cats evolved on the savanah about 8,000 years ago.'), - pht( - 'Cats have a tail, two feet, between one and three ears, and two '. - 'other feet.'), - pht('Cats use their keen sense of smell to avoid feeling empathy.'), - pht('The first cats evolved in swamps about 65 years ago.'), - pht( - 'You can tell how warm a cat is by examining the coloration: cooler '. - 'areas are darker.'), - pht( - 'Cat tails are flexible because they contain thousands of tiny '. - 'bones.'), - pht( - 'A cattail is a wetland plant with an appearance that resembles '. - 'the tail of a cat.'), - pht( - 'Cats must eat a diet rich in fish to replace the tiny bones in '. - 'their tails.'), - pht('Cats are stealthy predators and nearly invisible to radar.'), - pht( - 'Cats use a special type of magnetism to help them land on their '. - 'feet.'), - pht( - 'A cat can run seven times faster than a human, but only for a '. - 'short distance.'), - pht( - 'The largest recorded cat was nearly 11 inches long from nose to '. - 'tail.'), - pht( - 'Not all cats can retract their claws, but most of them can.'), - pht( - 'In the wild, cats and racoons sometimes hunt together in packs.'), - pht( - 'The Spanish word for cat is "cato". The biggest cat is called '. - '"el cato".'), - pht( - 'The Japanese word for cat is "kome", which is also the word for '. - 'rice. Japanese cats love to eat rice, so the two are synonymous.'), - pht('Cats have five pointy ends.'), - pht('cat -A can find mice hiding in files.'), - pht('A cat\'s visual, olfactory, and auditory senses, '. - 'Contribute to their hunting skills and natural defenses.'), - pht( - 'Cats with high self-esteem seek out high perches '. - 'to launch their attacks. Watch out!'), - pht('Cats prefer vanilla ice cream.'), - pht('Taco cat spelled backwards is taco cat.'), - pht( - 'Cats will often bring you their prey because they feel sorry '. - 'for your inability to hunt.'), - pht('Cats spend most of their time plotting to kill their owner.'), - ); - } - - private function selectFact(array $facts) { - // This is a simple pseudorandom number generator that avoids touching - // srand(), because it would seed it to a highly predictable value. It - // selects a new fact every day. - - $seed = ((int)date('Y') * 366) + (int)date('z'); - for ($ii = 0; $ii < 32; $ii++) { - $seed = ((1664525 * $seed) + 1013904223) % (1 << 31); - } - - return $facts[$seed % count($facts)]; - } - - -} From 98a29f3de90af1b40924934c5fd6b8ee1e15bd32 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 20 Jan 2017 16:56:30 +0000 Subject: [PATCH 28/31] Put "View Edit History" above "Remove Comment" in timeline comment action dropdown Summary: Fixes T12131. Test Plan: {F2449700} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12131 Differential Revision: https://secure.phabricator.com/D17234 --- src/view/phui/PHUITimelineEventView.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/view/phui/PHUITimelineEventView.php b/src/view/phui/PHUITimelineEventView.php index 41113a1f14..142ea1e87d 100644 --- a/src/view/phui/PHUITimelineEventView.php +++ b/src/view/phui/PHUITimelineEventView.php @@ -646,6 +646,14 @@ final class PHUITimelineEventView extends AphrontView { } } + if ($this->getIsEdited()) { + $items[] = id(new PhabricatorActionView()) + ->setIcon('fa-list') + ->setHref('/transactions/history/'.$xaction_phid.'/') + ->setName(pht('View Edit History')) + ->setWorkflow(true); + } + if ($this->getIsRemovable()) { $items[] = id(new PhabricatorActionView()) ->setType(PhabricatorActionView::TYPE_DIVIDER); @@ -663,14 +671,6 @@ final class PHUITimelineEventView extends AphrontView { } - if ($this->getIsEdited()) { - $items[] = id(new PhabricatorActionView()) - ->setIcon('fa-list') - ->setHref('/transactions/history/'.$xaction_phid.'/') - ->setName(pht('View Edit History')) - ->setWorkflow(true); - } - return $items; } From 8113b7691089062013229b7325a48f313065e027 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 20 Jan 2017 11:03:09 -0800 Subject: [PATCH 29/31] Validate menu item fields (links, projects, dashboards, applications, forms, etc) Summary: Ref T12128. This adds validation to menu items. This feels a touch flimsy-ish (kind of copy/paste heavy?) but maybe it can be cleaned up a bit once some similar lightweight modular item types (build steps in Harbormaster, blueprints in Drydock) convert. Test Plan: - Tried to create each item with errors (no dashboard, no project, etc). Got appropriate form errors. - Created valid items of each type. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12128 Differential Revision: https://secure.phabricator.com/D17235 --- .../PhabricatorProfileMenuEditEngine.php | 43 ++++++++++++++ .../editor/PhabricatorProfileMenuEditor.php | 35 ++++++++++++ .../PhabricatorApplicationProfileMenuItem.php | 51 ++++++++++++++++- .../PhabricatorDashboardProfileMenuItem.php | 49 +++++++++++++++- .../PhabricatorEditEngineProfileMenuItem.php | 56 ++++++++++++++++++- .../PhabricatorLinkProfileMenuItem.php | 56 ++++++++++++++++++- .../menuitem/PhabricatorProfileMenuItem.php | 37 ++++++++++++ .../PhabricatorProjectProfileMenuItem.php | 48 +++++++++++++++- ...habricatorProfileMenuItemConfiguration.php | 24 ++++++++ .../editengine/PhabricatorEditEngine.php | 4 ++ 10 files changed, 396 insertions(+), 7 deletions(-) diff --git a/src/applications/search/editor/PhabricatorProfileMenuEditEngine.php b/src/applications/search/editor/PhabricatorProfileMenuEditEngine.php index 176938afb6..b21d03cbd1 100644 --- a/src/applications/search/editor/PhabricatorProfileMenuEditEngine.php +++ b/src/applications/search/editor/PhabricatorProfileMenuEditEngine.php @@ -149,4 +149,47 @@ final class PhabricatorProfileMenuEditEngine return $fields; } + protected function getValidationExceptionShortMessage( + PhabricatorApplicationTransactionValidationException $ex, + PhabricatorEditField $field) { + + // Menu item properties all have the same transaction type, so we need + // to make sure errors about a specific property (like the URI for a + // link) are only applied to the field for that particular property. If + // we don't do this, the red error text like "Required" will display + // next to every field. + + $property_type = + PhabricatorProfileMenuItemConfigurationTransaction::TYPE_PROPERTY; + + $xaction_type = $field->getTransactionType(); + if ($xaction_type == $property_type) { + $field_key = $field->getKey(); + foreach ($ex->getErrors() as $error) { + if ($error->getType() !== $xaction_type) { + continue; + } + + $xaction = $error->getTransaction(); + if (!$xaction) { + continue; + } + + $xaction_setting = $xaction->getMetadataValue('property.key'); + if ($xaction_setting != $field_key) { + continue; + } + + $short_message = $error->getShortMessage(); + if ($short_message !== null) { + return $short_message; + } + } + + return null; + } + + return parent::getValidationExceptionShortMessage($ex, $field); + } + } diff --git a/src/applications/search/editor/PhabricatorProfileMenuEditor.php b/src/applications/search/editor/PhabricatorProfileMenuEditor.php index d91bba272b..308cde0db5 100644 --- a/src/applications/search/editor/PhabricatorProfileMenuEditor.php +++ b/src/applications/search/editor/PhabricatorProfileMenuEditor.php @@ -87,4 +87,39 @@ final class PhabricatorProfileMenuEditor return parent::applyCustomExternalTransaction($object, $xaction); } + protected function validateTransaction( + PhabricatorLiskDAO $object, + $type, + array $xactions) { + + $errors = parent::validateTransaction($object, $type, $xactions); + + $actor = $this->getActor(); + $menu_item = $object->getMenuItem(); + $menu_item->setViewer($actor); + + switch ($type) { + case PhabricatorProfileMenuItemConfigurationTransaction::TYPE_PROPERTY: + $key_map = array(); + foreach ($xactions as $xaction) { + $xaction_key = $xaction->getMetadataValue('property.key'); + $old = $this->getCustomTransactionOldValue($object, $xaction); + $new = $xaction->getNewValue(); + $key_map[$xaction_key][] = array( + 'xaction' => $xaction, + 'old' => $old, + 'new' => $new, + ); + } + + foreach ($object->validateTransactions($key_map) as $error) { + $errors[] = $error; + } + break; + } + + return $errors; + } + + } diff --git a/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php index a207f57f3a..2cd6440cf5 100644 --- a/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php @@ -5,6 +5,8 @@ final class PhabricatorApplicationProfileMenuItem const MENUITEMKEY = 'application'; + const FIELD_APPLICATION = 'application'; + public function getMenuItemTypeIcon() { return 'fa-globe'; } @@ -32,10 +34,11 @@ final class PhabricatorApplicationProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { return array( id(new PhabricatorDatasourceEditField()) - ->setKey('application') + ->setKey(self::FIELD_APPLICATION) ->setLabel(pht('Application')) ->setIsRequired(true) ->setDatasource(new PhabricatorApplicationDatasource()) + ->setIsRequired(true) ->setSingleValue($config->getMenuItemProperty('application')), ); } @@ -44,6 +47,7 @@ final class PhabricatorApplicationProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { $viewer = $this->getViewer(); $phid = $config->getMenuItemProperty('application'); + $app = id(new PhabricatorApplicationQuery()) ->setViewer($viewer) ->withPHIDs(array($phid)) @@ -77,4 +81,49 @@ final class PhabricatorApplicationProfileMenuItem ); } + public function validateTransactions( + PhabricatorProfileMenuItemConfiguration $config, + $field_key, + $value, + array $xactions) { + + $viewer = $this->getViewer(); + $errors = array(); + + if ($field_key == self::FIELD_APPLICATION) { + if ($this->isEmptyTransaction($value, $xactions)) { + $errors[] = $this->newRequiredError( + pht('You must choose an application.'), + $field_key); + } + + foreach ($xactions as $xaction) { + $new = $xaction['new']; + + if (!$new) { + continue; + } + + if ($new === $value) { + continue; + } + + $applications = id(new PhabricatorApplicationQuery()) + ->setViewer($viewer) + ->withPHIDs(array($new)) + ->execute(); + if (!$applications) { + $errors[] = $this->newInvalidError( + pht( + 'Application "%s" is not a valid application which you have '. + 'permission to see.', + $new), + $xaction['xaction']); + } + } + } + + return $errors; + } + } diff --git a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php index 9b9d1dff7c..2aab6eee34 100644 --- a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php @@ -5,6 +5,8 @@ final class PhabricatorDashboardProfileMenuItem const MENUITEMKEY = 'dashboard'; + const FIELD_DASHBOARD = 'dashboardPHID'; + private $dashboard; public function getMenuItemTypeIcon() { @@ -75,7 +77,7 @@ final class PhabricatorDashboardProfileMenuItem ->setLabel(pht('Name')) ->setValue($this->getName($config)), id(new PhabricatorDatasourceEditField()) - ->setKey('dashboardPHID') + ->setKey(self::FIELD_DASHBOARD) ->setLabel(pht('Dashboard')) ->setIsRequired(true) ->setDatasource(new PhabricatorDashboardDatasource()) @@ -110,4 +112,49 @@ final class PhabricatorDashboardProfileMenuItem ); } + public function validateTransactions( + PhabricatorProfileMenuItemConfiguration $config, + $field_key, + $value, + array $xactions) { + + $viewer = $this->getViewer(); + $errors = array(); + + if ($field_key == self::FIELD_DASHBOARD) { + if ($this->isEmptyTransaction($value, $xactions)) { + $errors[] = $this->newRequiredError( + pht('You must choose a dashboard.'), + $field_key); + } + + foreach ($xactions as $xaction) { + $new = $xaction['new']; + + if (!$new) { + continue; + } + + if ($new === $value) { + continue; + } + + $dashboards = id(new PhabricatorDashboardQuery()) + ->setViewer($viewer) + ->withPHIDs(array($new)) + ->execute(); + if (!$dashboards) { + $errors[] = $this->newInvalidError( + pht( + 'Dashboard "%s" is not a valid dashboard which you have '. + 'permission to see.', + $new), + $xaction['xaction']); + } + } + } + + return $errors; + } + } diff --git a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php index 071efa80dd..db4804996a 100644 --- a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php @@ -5,6 +5,8 @@ final class PhabricatorEditEngineProfileMenuItem const MENUITEMKEY = 'editengine'; + const FIELD_FORM = 'formKey'; + private $form; public function getMenuItemTypeIcon() { @@ -51,7 +53,8 @@ final class PhabricatorEditEngineProfileMenuItem foreach ($items as $item) { $key = $item->getMenuItemProperty('formKey'); - list($engine_key, $form_key) = explode('/', $key); + list($engine_key, $form_key) = PhabricatorEditEngine::splitFullKey($key); + if (is_numeric($form_key)) { $form = idx($form_ids, $form_key, null); $item->getMenuItem()->attachForm($form); @@ -83,7 +86,7 @@ final class PhabricatorEditEngineProfileMenuItem ->setLabel(pht('Name')) ->setValue($this->getName($config)), id(new PhabricatorDatasourceEditField()) - ->setKey('formKey') + ->setKey(self::FIELD_FORM) ->setLabel(pht('Form')) ->setIsRequired(true) ->setDatasource(new PhabricatorEditEngineDatasource()) @@ -120,4 +123,53 @@ final class PhabricatorEditEngineProfileMenuItem ); } + public function validateTransactions( + PhabricatorProfileMenuItemConfiguration $config, + $field_key, + $value, + array $xactions) { + + $viewer = $this->getViewer(); + $errors = array(); + + if ($field_key == self::FIELD_FORM) { + if ($this->isEmptyTransaction($value, $xactions)) { + $errors[] = $this->newRequiredError( + pht('You must choose a form.'), + $field_key); + } + + foreach ($xactions as $xaction) { + $new = $xaction['new']; + + if (!$new) { + continue; + } + + if ($new === $value) { + continue; + } + + list($engine_key, $form_key) = PhabricatorEditEngine::splitFullKey( + $new); + + $forms = id(new PhabricatorEditEngineConfigurationQuery()) + ->setViewer($viewer) + ->withEngineKeys(array($engine_key)) + ->withIdentifiers(array($form_key)) + ->execute(); + if (!$forms) { + $errors[] = $this->newInvalidError( + pht( + 'Form "%s" is not a valid form which you have permission to '. + 'see.', + $new), + $xaction['xaction']); + } + } + } + + return $errors; + } + } diff --git a/src/applications/search/menuitem/PhabricatorLinkProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorLinkProfileMenuItem.php index 5571788cc1..3b136321c2 100644 --- a/src/applications/search/menuitem/PhabricatorLinkProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorLinkProfileMenuItem.php @@ -5,6 +5,9 @@ final class PhabricatorLinkProfileMenuItem const MENUITEMKEY = 'link'; + const FIELD_URI = 'uri'; + const FIELD_NAME = 'name'; + public function getMenuItemTypeIcon() { return 'fa-link'; } @@ -26,12 +29,12 @@ final class PhabricatorLinkProfileMenuItem PhabricatorProfileMenuItemConfiguration $config) { return array( id(new PhabricatorTextEditField()) - ->setKey('name') + ->setKey(self::FIELD_NAME) ->setLabel(pht('Name')) ->setIsRequired(true) ->setValue($this->getLinkName($config)), id(new PhabricatorTextEditField()) - ->setKey('uri') + ->setKey(self::FIELD_URI) ->setLabel(pht('URI')) ->setIsRequired(true) ->setValue($this->getLinkURI($config)), @@ -91,4 +94,53 @@ final class PhabricatorLinkProfileMenuItem ); } + public function validateTransactions( + PhabricatorProfileMenuItemConfiguration $config, + $field_key, + $value, + array $xactions) { + + $viewer = $this->getViewer(); + $errors = array(); + + if ($field_key == self::FIELD_NAME) { + if ($this->isEmptyTransaction($value, $xactions)) { + $errors[] = $this->newRequiredError( + pht('You must choose a link name.'), + $field_key); + } + } + + if ($field_key == self::FIELD_URI) { + if ($this->isEmptyTransaction($value, $xactions)) { + $errors[] = $this->newRequiredError( + pht('You must choose a URI to link to.'), + $field_key); + } + + foreach ($xactions as $xaction) { + $new = $xaction['new']; + + if (!$new) { + continue; + } + + if ($new === $value) { + continue; + } + + if (!$this->isValidLinkURI($new)) { + $errors[] = $this->newInvalidError( + pht( + 'URI "%s" is not a valid link URI. It should be a full, valid '. + 'URI beginning with a protocol like "%s".', + $new, + 'https://'), + $xaction['xaction']); + } + } + } + + return $errors; + } } diff --git a/src/applications/search/menuitem/PhabricatorProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorProfileMenuItem.php index c47d9afe8e..05fa6543d3 100644 --- a/src/applications/search/menuitem/PhabricatorProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorProfileMenuItem.php @@ -70,4 +70,41 @@ abstract class PhabricatorProfileMenuItem extends Phobject { return new PHUIListItemView(); } + public function valdateTransactions( + PhabricatorProfileMenuItemConfiguration $config, + $field_key, + $value, + array $xactions) { + return array(); + } + + final protected function isEmptyTransaction($value, array $xactions) { + $result = $value; + foreach ($xactions as $xaction) { + $result = $xaction['new']; + } + + return !strlen($result); + } + + final protected function newError($title, $message, $xaction = null) { + return new PhabricatorApplicationTransactionValidationError( + PhabricatorProfileMenuItemConfigurationTransaction::TYPE_PROPERTY, + $title, + $message, + $xaction); + } + + final protected function newRequiredError($message, $type) { + $xaction = id(new PhabricatorProfileMenuItemConfigurationTransaction()) + ->setMetadataValue('property.key', $type); + + return $this->newError(pht('Required'), $message, $xaction) + ->setIsMissingFieldError(true); + } + + final protected function newInvalidError($message, $xaction = null) { + return $this->newError(pht('Invalid'), $message, $xaction); + } + } diff --git a/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php index e47d97677f..364a68e4b8 100644 --- a/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php @@ -4,6 +4,7 @@ final class PhabricatorProjectProfileMenuItem extends PhabricatorProfileMenuItem { const MENUITEMKEY = 'project'; + const FIELD_PROJECT = 'project'; private $project; @@ -76,7 +77,7 @@ final class PhabricatorProjectProfileMenuItem ->setLabel(pht('Name')) ->setValue($this->getName($config)), id(new PhabricatorDatasourceEditField()) - ->setKey('project') + ->setKey(self::FIELD_PROJECT) ->setLabel(pht('Project')) ->setIsRequired(true) ->setDatasource(new PhabricatorProjectDatasource()) @@ -111,4 +112,49 @@ final class PhabricatorProjectProfileMenuItem ); } + public function validateTransactions( + PhabricatorProfileMenuItemConfiguration $config, + $field_key, + $value, + array $xactions) { + + $viewer = $this->getViewer(); + $errors = array(); + + if ($field_key == self::FIELD_PROJECT) { + if ($this->isEmptyTransaction($value, $xactions)) { + $errors[] = $this->newRequiredError( + pht('You must choose a project.'), + $field_key); + } + + foreach ($xactions as $xaction) { + $new = $xaction['new']; + + if (!$new) { + continue; + } + + if ($new === $value) { + continue; + } + + $projects = id(new PhabricatorProjectQuery()) + ->setViewer($viewer) + ->withPHIDs(array($new)) + ->execute(); + if (!$projects) { + $errors[] = $this->newInvalidError( + pht( + 'Project "%s" is not a valid project which you have '. + 'permission to see.', + $new), + $xaction['xaction']); + } + } + } + + return $errors; + } + } diff --git a/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php b/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php index e1571ee6f6..107fa63c72 100644 --- a/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php +++ b/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php @@ -126,6 +126,30 @@ final class PhabricatorProfileMenuItemConfiguration return $this->getMenuItem()->willBuildNavigationItems($items); } + public function validateTransactions(array $map) { + $item = $this->getMenuItem(); + + $fields = $item->buildEditEngineFields($this); + $errors = array(); + foreach ($fields as $field) { + $field_key = $field->getKey(); + + $xactions = idx($map, $field_key, array()); + $value = $this->getMenuItemProperty($field_key); + + $field_errors = $item->validateTransactions( + $this, + $field_key, + $value, + $xactions); + foreach ($field_errors as $error) { + $errors[] = $error; + } + } + + return $errors; + } + public function getSortVector() { // Sort custom items above global items. if ($this->getCustomPHID()) { diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php index 65901e1294..e594ae4b67 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngine.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php @@ -95,6 +95,10 @@ abstract class PhabricatorEditEngine return $keys; } + public static function splitFullKey($full_key) { + return explode('/', $full_key, 2); + } + public function getQuickCreateOrderVector() { return id(new PhutilSortVector()) ->addString($this->getObjectCreateShortText()); From d24739ee3cfa9b18594a2298620e0a3cb12f87fb Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 20 Jan 2017 11:42:29 -0800 Subject: [PATCH 30/31] Minor consistency/order updates for menu items which reference other objects Summary: See T11957#208140. - Let Applications have a custom name, like other object items (for example, so you can call Maniphest "Tasks" if you prefer). - Put the optional name field after the required typeahead field for these items. - (I left "Link" in "Name, URI" order since both are required, but there's maybe an argument for swapping them?) Test Plan: - Created each type of item, saw "thing, name" order. - Created an application with a cusotm name, saw custom name. - Removed custom name, saw original name. Reviewers: chad Reviewed By: chad Differential Revision: https://secure.phabricator.com/D17236 --- .../PhabricatorApplicationProfileMenuItem.php | 27 ++++++++++++++----- .../PhabricatorDashboardProfileMenuItem.php | 8 +++--- .../PhabricatorEditEngineProfileMenuItem.php | 8 +++--- .../PhabricatorProjectProfileMenuItem.php | 8 +++--- 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php index 2cd6440cf5..1c4c8410f3 100644 --- a/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php @@ -21,13 +21,17 @@ final class PhabricatorApplicationProfileMenuItem public function getDisplayName( PhabricatorProfileMenuItemConfiguration $config) { - $app = $this->getApplication($config); - if ($app) { - return $app->getName(); - } else { - return pht('(Uninstalled Application)'); + $application = $this->getApplication($config); + if (!$application) { + return pht('(Restricted/Invalid Application)'); } - return $app->getName(); + + $name = $this->getName($config); + if (strlen($name)) { + return $name; + } + + return $application->getName(); } public function buildEditEngineFields( @@ -40,9 +44,18 @@ final class PhabricatorApplicationProfileMenuItem ->setDatasource(new PhabricatorApplicationDatasource()) ->setIsRequired(true) ->setSingleValue($config->getMenuItemProperty('application')), + id(new PhabricatorTextEditField()) + ->setKey('name') + ->setLabel(pht('Name')) + ->setValue($this->getName($config)), ); } + private function getName( + PhabricatorProfileMenuItemConfiguration $config) { + return $config->getMenuItemProperty('name'); + } + private function getApplication( PhabricatorProfileMenuItemConfiguration $config) { $viewer = $this->getViewer(); @@ -73,7 +86,7 @@ final class PhabricatorApplicationProfileMenuItem $item = $this->newItem() ->setHref($app->getApplicationURI()) - ->setName($app->getName()) + ->setName($this->getDisplayName($config)) ->setIcon($app->getIcon()); return array( diff --git a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php index 2aab6eee34..c9a13bd4ab 100644 --- a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php @@ -72,16 +72,16 @@ final class PhabricatorDashboardProfileMenuItem public function buildEditEngineFields( PhabricatorProfileMenuItemConfiguration $config) { return array( - id(new PhabricatorTextEditField()) - ->setKey('name') - ->setLabel(pht('Name')) - ->setValue($this->getName($config)), id(new PhabricatorDatasourceEditField()) ->setKey(self::FIELD_DASHBOARD) ->setLabel(pht('Dashboard')) ->setIsRequired(true) ->setDatasource(new PhabricatorDashboardDatasource()) ->setSingleValue($config->getMenuItemProperty('dashboardPHID')), + id(new PhabricatorTextEditField()) + ->setKey('name') + ->setLabel(pht('Name')) + ->setValue($this->getName($config)), ); } diff --git a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php index db4804996a..4b840d39e3 100644 --- a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php @@ -81,16 +81,16 @@ final class PhabricatorEditEngineProfileMenuItem public function buildEditEngineFields( PhabricatorProfileMenuItemConfiguration $config) { return array( - id(new PhabricatorTextEditField()) - ->setKey('name') - ->setLabel(pht('Name')) - ->setValue($this->getName($config)), id(new PhabricatorDatasourceEditField()) ->setKey(self::FIELD_FORM) ->setLabel(pht('Form')) ->setIsRequired(true) ->setDatasource(new PhabricatorEditEngineDatasource()) ->setSingleValue($config->getMenuItemProperty('formKey')), + id(new PhabricatorTextEditField()) + ->setKey('name') + ->setLabel(pht('Name')) + ->setValue($this->getName($config)), ); } diff --git a/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php index 364a68e4b8..aadabd179a 100644 --- a/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorProjectProfileMenuItem.php @@ -72,16 +72,16 @@ final class PhabricatorProjectProfileMenuItem public function buildEditEngineFields( PhabricatorProfileMenuItemConfiguration $config) { return array( - id(new PhabricatorTextEditField()) - ->setKey('name') - ->setLabel(pht('Name')) - ->setValue($this->getName($config)), id(new PhabricatorDatasourceEditField()) ->setKey(self::FIELD_PROJECT) ->setLabel(pht('Project')) ->setIsRequired(true) ->setDatasource(new PhabricatorProjectDatasource()) ->setSingleValue($config->getMenuItemProperty('project')), + id(new PhabricatorTextEditField()) + ->setKey('name') + ->setLabel(pht('Name')) + ->setValue($this->getName($config)), ); } From ddf82a815b9a07e901870c2f4d5b7582af7b4d82 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 20 Jan 2017 12:06:12 -0800 Subject: [PATCH 31/31] Remove duplicate setIsRequired() Summary: See D17235. Test Plan: tarnation Reviewers: chad Reviewed By: chad Differential Revision: https://secure.phabricator.com/D17237 --- .../search/menuitem/PhabricatorApplicationProfileMenuItem.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php index 1c4c8410f3..7d87bc25d4 100644 --- a/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php @@ -40,7 +40,6 @@ final class PhabricatorApplicationProfileMenuItem id(new PhabricatorDatasourceEditField()) ->setKey(self::FIELD_APPLICATION) ->setLabel(pht('Application')) - ->setIsRequired(true) ->setDatasource(new PhabricatorApplicationDatasource()) ->setIsRequired(true) ->setSingleValue($config->getMenuItemProperty('application')),