diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ 'names' => array( 'conpherence.pkg.css' => '3c8a0668', 'conpherence.pkg.js' => '020aebcf', - 'core.pkg.css' => '7e6e954b', + 'core.pkg.css' => 'a1c2d49b', 'core.pkg.js' => 'a747b035', 'differential.pkg.css' => '8d8360fb', 'differential.pkg.js' => '67e02996', @@ -132,7 +132,7 @@ 'rsrc/css/phui/object-item/phui-oi-color.css' => 'b517bfa0', 'rsrc/css/phui/object-item/phui-oi-drag-ui.css' => 'da15d3dc', 'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '490e2e2e', - 'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'a65865a7', + 'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'f14f2422', 'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => '6a30fa46', 'rsrc/css/phui/phui-action-list.css' => 'c4972757', 'rsrc/css/phui/phui-action-panel.css' => '6c386cbf', @@ -853,7 +853,7 @@ 'phui-oi-color-css' => 'b517bfa0', 'phui-oi-drag-ui-css' => 'da15d3dc', 'phui-oi-flush-ui-css' => '490e2e2e', - 'phui-oi-list-view-css' => 'a65865a7', + 'phui-oi-list-view-css' => 'f14f2422', 'phui-oi-simple-ui-css' => '6a30fa46', 'phui-pager-css' => 'd022c7ad', 'phui-pinboard-view-css' => '1f08f5d8', diff --git a/src/applications/dashboard/engine/PhabricatorDashboardPortalProfileMenuEngine.php b/src/applications/dashboard/engine/PhabricatorDashboardPortalProfileMenuEngine.php --- a/src/applications/dashboard/engine/PhabricatorDashboardPortalProfileMenuEngine.php +++ b/src/applications/dashboard/engine/PhabricatorDashboardPortalProfileMenuEngine.php @@ -24,7 +24,8 @@ $items[] = $this->newItem() ->setMenuItemKey(PhabricatorDashboardPortalMenuItem::MENUITEMKEY) - ->setBuiltinKey('manage'); + ->setBuiltinKey('manage') + ->setIsTailItem(true); return $items; } diff --git a/src/applications/dashboard/menuitem/PhabricatorDashboardPortalMenuItem.php b/src/applications/dashboard/menuitem/PhabricatorDashboardPortalMenuItem.php --- a/src/applications/dashboard/menuitem/PhabricatorDashboardPortalMenuItem.php +++ b/src/applications/dashboard/menuitem/PhabricatorDashboardPortalMenuItem.php @@ -6,7 +6,7 @@ const MENUITEMKEY = 'portal'; public function getMenuItemTypeIcon() { - return 'fa-compass'; + return 'fa-pencil'; } public function getDefaultName() { diff --git a/src/applications/home/menuitem/PhabricatorHomeLauncherProfileMenuItem.php b/src/applications/home/menuitem/PhabricatorHomeLauncherProfileMenuItem.php --- a/src/applications/home/menuitem/PhabricatorHomeLauncherProfileMenuItem.php +++ b/src/applications/home/menuitem/PhabricatorHomeLauncherProfileMenuItem.php @@ -13,6 +13,10 @@ return pht('More Applications'); } + public function getMenuItemTypeIcon() { + return 'fa-ellipsis-h'; + } + public function canHideMenuItem( PhabricatorProfileMenuItemConfiguration $config) { return false; @@ -50,7 +54,7 @@ $viewer = $this->getViewer(); $name = $this->getDisplayName($config); - $icon = 'fa-globe'; + $icon = 'fa-ellipsis-h'; $href = '/applications/'; $item = $this->newItem() diff --git a/src/applications/home/menuitem/PhabricatorHomeProfileMenuItem.php b/src/applications/home/menuitem/PhabricatorHomeProfileMenuItem.php --- a/src/applications/home/menuitem/PhabricatorHomeProfileMenuItem.php +++ b/src/applications/home/menuitem/PhabricatorHomeProfileMenuItem.php @@ -13,6 +13,10 @@ return pht('Home'); } + public function getMenuItemTypeIcon() { + return 'fa-home'; + } + public function canMakeDefault( PhabricatorProfileMenuItemConfiguration $config) { return true; diff --git a/src/applications/project/engine/PhabricatorProjectProfileMenuEngine.php b/src/applications/project/engine/PhabricatorProjectProfileMenuEngine.php --- a/src/applications/project/engine/PhabricatorProjectProfileMenuEngine.php +++ b/src/applications/project/engine/PhabricatorProjectProfileMenuEngine.php @@ -22,7 +22,8 @@ $items[] = $this->newItem() ->setBuiltinKey(PhabricatorProject::ITEM_PICTURE) - ->setMenuItemKey(PhabricatorProjectPictureProfileMenuItem::MENUITEMKEY); + ->setMenuItemKey(PhabricatorProjectPictureProfileMenuItem::MENUITEMKEY) + ->setIsHeadItem(true); $items[] = $this->newItem() ->setBuiltinKey(PhabricatorProject::ITEM_PROFILE) @@ -47,7 +48,8 @@ $items[] = $this->newItem() ->setBuiltinKey(PhabricatorProject::ITEM_MANAGE) - ->setMenuItemKey(PhabricatorProjectManageProfileMenuItem::MENUITEMKEY); + ->setMenuItemKey(PhabricatorProjectManageProfileMenuItem::MENUITEMKEY) + ->setIsTailItem(true); return $items; } diff --git a/src/applications/project/menuitem/PhabricatorProjectDetailsProfileMenuItem.php b/src/applications/project/menuitem/PhabricatorProjectDetailsProfileMenuItem.php --- a/src/applications/project/menuitem/PhabricatorProjectDetailsProfileMenuItem.php +++ b/src/applications/project/menuitem/PhabricatorProjectDetailsProfileMenuItem.php @@ -13,6 +13,10 @@ return pht('Project Details'); } + public function getMenuItemTypeIcon() { + return 'fa-file-text-o'; + } + public function canHideMenuItem( PhabricatorProfileMenuItemConfiguration $config) { return false; diff --git a/src/applications/project/menuitem/PhabricatorProjectManageProfileMenuItem.php b/src/applications/project/menuitem/PhabricatorProjectManageProfileMenuItem.php --- a/src/applications/project/menuitem/PhabricatorProjectManageProfileMenuItem.php +++ b/src/applications/project/menuitem/PhabricatorProjectManageProfileMenuItem.php @@ -13,6 +13,10 @@ return pht('Manage'); } + public function getMenuItemTypeIcon() { + return 'fa-cog'; + } + public function canHideMenuItem( PhabricatorProfileMenuItemConfiguration $config) { return false; diff --git a/src/applications/project/menuitem/PhabricatorProjectMembersProfileMenuItem.php b/src/applications/project/menuitem/PhabricatorProjectMembersProfileMenuItem.php --- a/src/applications/project/menuitem/PhabricatorProjectMembersProfileMenuItem.php +++ b/src/applications/project/menuitem/PhabricatorProjectMembersProfileMenuItem.php @@ -13,6 +13,10 @@ return pht('Members'); } + public function getMenuItemTypeIcon() { + return 'fa-users'; + } + public function getDisplayName( PhabricatorProfileMenuItemConfiguration $config) { $name = $config->getMenuItemProperty('name'); diff --git a/src/applications/project/menuitem/PhabricatorProjectPictureProfileMenuItem.php b/src/applications/project/menuitem/PhabricatorProjectPictureProfileMenuItem.php --- a/src/applications/project/menuitem/PhabricatorProjectPictureProfileMenuItem.php +++ b/src/applications/project/menuitem/PhabricatorProjectPictureProfileMenuItem.php @@ -13,6 +13,10 @@ return pht('Project Picture'); } + public function getMenuItemTypeIcon() { + return 'fa-image'; + } + public function canHideMenuItem( PhabricatorProfileMenuItemConfiguration $config) { return false; diff --git a/src/applications/project/menuitem/PhabricatorProjectSubprojectsProfileMenuItem.php b/src/applications/project/menuitem/PhabricatorProjectSubprojectsProfileMenuItem.php --- a/src/applications/project/menuitem/PhabricatorProjectSubprojectsProfileMenuItem.php +++ b/src/applications/project/menuitem/PhabricatorProjectSubprojectsProfileMenuItem.php @@ -13,6 +13,10 @@ return pht('Subprojects'); } + public function getMenuItemTypeIcon() { + return 'fa-sitemap'; + } + public function shouldEnableForObject($object) { if ($object->isMilestone()) { return false; diff --git a/src/applications/project/menuitem/PhabricatorProjectWorkboardProfileMenuItem.php b/src/applications/project/menuitem/PhabricatorProjectWorkboardProfileMenuItem.php --- a/src/applications/project/menuitem/PhabricatorProjectWorkboardProfileMenuItem.php +++ b/src/applications/project/menuitem/PhabricatorProjectWorkboardProfileMenuItem.php @@ -13,6 +13,10 @@ return pht('Workboard'); } + public function getMenuItemTypeIcon() { + return 'fa-columns'; + } + public function canMakeDefault( PhabricatorProfileMenuItemConfiguration $config) { return true; diff --git a/src/applications/search/engine/PhabricatorProfileMenuEngine.php b/src/applications/search/engine/PhabricatorProfileMenuEngine.php --- a/src/applications/search/engine/PhabricatorProfileMenuEngine.php +++ b/src/applications/search/engine/PhabricatorProfileMenuEngine.php @@ -460,6 +460,12 @@ // stored config: it corresponds to an out-of-date or uninstalled // item. if (isset($items[$builtin_key])) { + $builtin_item = $items[$builtin_key]; + + // Copy runtime properties from the builtin item to the stored item. + $stored_item->setIsHeadItem($builtin_item->getIsHeadItem()); + $stored_item->setIsTailItem($builtin_item->getIsTailItem()); + $items[$builtin_key] = $stored_item; } else { continue; @@ -802,6 +808,7 @@ ->setID($list_id) ->setNoDataString(pht('This menu currently has no items.')); + $any_draggable = false; foreach ($items as $item) { $id = $item->getID(); $builtin_key = $item->getBuiltinKey(); @@ -822,14 +829,25 @@ $view->setHeader($name); $view->addAttribute($type); + $icon = $item->getMenuItem()->getMenuItemTypeIcon(); + if ($icon !== null) { + $view->setStatusIcon($icon); + } + if ($can_edit) { - $view - ->setGrippable(true) - ->addSigil('profile-menu-item') - ->setMetadata( - array( - 'key' => nonempty($id, $builtin_key), - )); + $can_move = (!$item->getIsHeadItem() && !$item->getIsTailItem()); + if ($can_move) { + $view + ->setGrippable(true) + ->addSigil('profile-menu-item') + ->setMetadata( + array( + 'key' => nonempty($id, $builtin_key), + )); + $any_draggable = true; + } else { + $view->setGrippable(false); + } if ($id) { $default_uri = $this->getItemURI("default/{$id}/"); @@ -944,8 +962,16 @@ ->setHeader(pht('Menu Items')) ->setHeaderIcon('fa-list'); + $list_header = id(new PHUIHeaderView()) + ->setHeader(pht('Current Menu Items')); + + if ($any_draggable) { + $list_header->setSubheader( + pht('Drag items in this list to reorder them.')); + } + $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Current Menu Items')) + ->setHeader($list_header) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setObjectList($list); @@ -1190,7 +1216,8 @@ protected function newManageItem() { return $this->newItem() ->setBuiltinKey(self::ITEM_MANAGE) - ->setMenuItemKey(PhabricatorManageProfileMenuItem::MENUITEMKEY); + ->setMenuItemKey(PhabricatorManageProfileMenuItem::MENUITEMKEY) + ->setIsTailItem(true); } public function adjustDefault($key) { diff --git a/src/applications/search/menuitem/PhabricatorLabelProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorLabelProfileMenuItem.php --- a/src/applications/search/menuitem/PhabricatorLabelProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorLabelProfileMenuItem.php @@ -7,7 +7,7 @@ const FIELD_NAME = 'name'; public function getMenuItemTypeIcon() { - return 'fa-map-signs'; + return 'fa-tag'; } public function getMenuItemTypeName() { diff --git a/src/applications/search/menuitem/PhabricatorManageProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorManageProfileMenuItem.php --- a/src/applications/search/menuitem/PhabricatorManageProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorManageProfileMenuItem.php @@ -13,6 +13,10 @@ return pht('Edit Menu'); } + public function getMenuItemTypeIcon() { + return 'fa-pencil'; + } + public function canHideMenuItem( PhabricatorProfileMenuItemConfiguration $config) { return false; diff --git a/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php b/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php --- a/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php +++ b/src/applications/search/storage/PhabricatorProfileMenuItemConfiguration.php @@ -17,6 +17,8 @@ private $profileObject = self::ATTACHABLE; private $menuItem = self::ATTACHABLE; + private $isHeadItem = false; + private $isTailItem = false; const VISIBILITY_DEFAULT = 'default'; const VISIBILITY_VISIBLE = 'visible'; @@ -158,6 +160,15 @@ $is_global = 1; } + // Sort "head" items above other items and "tail" items after other items. + if ($this->getIsHeadItem()) { + $force_position = 0; + } else if ($this->getIsTailItem()) { + $force_position = 2; + } else { + $force_position = 1; + } + // Sort items with an explicit order above items without an explicit order, // so any newly created builtins go to the bottom. $order = $this->getMenuItemOrder(); @@ -169,6 +180,7 @@ return id(new PhutilSortVector()) ->addInt($is_global) + ->addInt($force_position) ->addInt($has_order) ->addInt((int)$order) ->addInt((int)$this->getID()); @@ -207,6 +219,25 @@ return $this->getMenuItem()->newPageContent($this); } + public function setIsHeadItem($is_head_item) { + $this->isHeadItem = $is_head_item; + return $this; + } + + public function getIsHeadItem() { + return $this->isHeadItem; + } + + public function setIsTailItem($is_tail_item) { + $this->isTailItem = $is_tail_item; + return $this; + } + + public function getIsTailItem() { + return $this->isTailItem; + } + + /* -( PhabricatorPolicyInterface )----------------------------------------- */ diff --git a/src/view/phui/PHUIObjectItemView.php b/src/view/phui/PHUIObjectItemView.php --- a/src/view/phui/PHUIObjectItemView.php +++ b/src/view/phui/PHUIObjectItemView.php @@ -330,8 +330,14 @@ Javelin::initBehavior('phui-selectable-list'); } - if ($this->getGrippable()) { - $item_classes[] = 'phui-oi-grippable'; + $is_grippable = $this->getGrippable(); + if ($is_grippable !== null) { + $item_classes[] = 'phui-oi-has-grip'; + if ($is_grippable) { + $item_classes[] = 'phui-oi-grippable'; + } else { + $item_classes[] = 'phui-oi-ungrippable'; + } } if ($this->getImageURI()) { @@ -580,7 +586,7 @@ } $grippable = null; - if ($this->getGrippable()) { + if ($this->getGrippable() !== null) { $grippable = phutil_tag( 'div', array( diff --git a/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css b/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css --- a/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css +++ b/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css @@ -132,11 +132,15 @@ background: url('/rsrc/image/texture/grip.png') center center no-repeat; } +.phui-oi-ungrippable .phui-oi-grip { + opacity: 0.25; +} + .device .phui-oi-grip { display: none; } -.phui-oi-grippable .phui-oi-frame { +.phui-oi-has-grip .phui-oi-frame { padding-left: 16px; }