mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-18 19:40:55 +01:00
Allow profile menu items to be reordered
Summary: Ref T10054. Allows users to drag menu items to reorder them. Test Plan: Reordered a project menu. Reviewers: chad Reviewed By: chad Maniphest Tasks: T10054 Differential Revision: https://secure.phabricator.com/D15011
This commit is contained in:
parent
f24318f308
commit
1c5167dc74
7 changed files with 173 additions and 1 deletions
|
@ -424,6 +424,7 @@ return array(
|
|||
'rsrc/js/application/releeph/releeph-request-state-change.js' => 'a0b57eb8',
|
||||
'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'de2e896f',
|
||||
'rsrc/js/application/repository/repository-crossreference.js' => 'e5339c43',
|
||||
'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' => '1f2fcaf8',
|
||||
|
@ -663,6 +664,7 @@ return array(
|
|||
'javelin-behavior-remarkup-preview' => '4b700e9e',
|
||||
'javelin-behavior-reorder-applications' => '76b9fc3e',
|
||||
'javelin-behavior-reorder-columns' => 'e1d25dfb',
|
||||
'javelin-behavior-reorder-profile-menu-items' => 'e2e0a072',
|
||||
'javelin-behavior-repository-crossreference' => 'e5339c43',
|
||||
'javelin-behavior-scrollbar' => '834a1173',
|
||||
'javelin-behavior-search-reorder-queries' => 'e9581f08',
|
||||
|
@ -1933,6 +1935,13 @@ return array(
|
|||
'e292eaf4' => array(
|
||||
'javelin-install',
|
||||
),
|
||||
'e2e0a072' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
'javelin-dom',
|
||||
'phabricator-draggable-list',
|
||||
),
|
||||
'e379b58e' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
|
|
@ -642,6 +642,7 @@ abstract class PhabricatorApplication
|
|||
'(?P<panelAction>view)/(?P<panelID>[^/]+)/' => $controller,
|
||||
'(?P<panelAction>hide)/(?P<panelID>[^/]+)/' => $controller,
|
||||
'(?P<panelAction>configure)/' => $controller,
|
||||
'(?P<panelAction>reorder)/' => $controller,
|
||||
'(?P<panelAction>edit)/'.$edit_route => $controller,
|
||||
'(?P<panelAction>new)/(?<panelKey>[^/]+)/'.$edit_route => $controller,
|
||||
'(?P<panelAction>builtin)/(?<panelID>[^/]+)/'.$edit_route
|
||||
|
|
|
@ -15,6 +15,7 @@ final class PhabricatorProfilePanelEditor
|
|||
$types = parent::getTransactionTypes();
|
||||
|
||||
$types[] = PhabricatorProfilePanelConfigurationTransaction::TYPE_PROPERTY;
|
||||
$types[] = PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
@ -27,6 +28,8 @@ final class PhabricatorProfilePanelEditor
|
|||
case PhabricatorProfilePanelConfigurationTransaction::TYPE_PROPERTY:
|
||||
$key = $xaction->getMetadataValue('property.key');
|
||||
return $object->getPanelProperty($key, null);
|
||||
case PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER:
|
||||
return $object->getPanelOrder();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,6 +40,8 @@ final class PhabricatorProfilePanelEditor
|
|||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorProfilePanelConfigurationTransaction::TYPE_PROPERTY:
|
||||
return $xaction->getNewValue();
|
||||
case PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER:
|
||||
return (int)$xaction->getNewValue();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,6 +55,9 @@ final class PhabricatorProfilePanelEditor
|
|||
$value = $xaction->getNewValue();
|
||||
$object->setPanelProperty($key, $value);
|
||||
return;
|
||||
case PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER:
|
||||
$object->setPanelOrder($xaction->getNewValue());
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::applyCustomInternalTransaction($object, $xaction);
|
||||
|
@ -61,6 +69,7 @@ final class PhabricatorProfilePanelEditor
|
|||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorProfilePanelConfigurationTransaction::TYPE_PROPERTY:
|
||||
case PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER:
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -91,6 +91,9 @@ final class PhabricatorProfilePanelEngine extends Phobject {
|
|||
$content = $this->buildPanelConfigureContent($panel_list);
|
||||
$crumbs->addTextCrumb(pht('Configure Menu'));
|
||||
break;
|
||||
case 'reorder':
|
||||
$content = $this->buildPanelReorderContent($panel_list);
|
||||
break;
|
||||
case 'new':
|
||||
$panel_key = $request->getURIData('panelKey');
|
||||
$content = $this->buildPanelNewContent($panel_key);
|
||||
|
@ -204,6 +207,8 @@ final class PhabricatorProfilePanelEngine extends Phobject {
|
|||
$impl->setViewer($viewer);
|
||||
}
|
||||
|
||||
$panels = msort($panels, 'getSortKey');
|
||||
|
||||
// Normalize keys since callers shouldn't rely on this array being
|
||||
// partially keyed.
|
||||
$panels = array_values($panels);
|
||||
|
@ -305,6 +310,79 @@ final class PhabricatorProfilePanelEngine extends Phobject {
|
|||
return "/project/{$id}/panel/{$path}";
|
||||
}
|
||||
|
||||
private function buildPanelReorderContent(array $panels) {
|
||||
$viewer = $this->getViewer();
|
||||
$object = $this->getProfileObject();
|
||||
|
||||
PhabricatorPolicyFilter::requireCapability(
|
||||
$viewer,
|
||||
$object,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$controller = $this->getController();
|
||||
$request = $controller->getRequest();
|
||||
|
||||
$request->validateCSRF();
|
||||
|
||||
$order = $request->getStrList('order');
|
||||
|
||||
$by_builtin = array();
|
||||
$by_id = array();
|
||||
|
||||
foreach ($panels as $key => $panel) {
|
||||
$id = $panel->getID();
|
||||
if ($id) {
|
||||
$by_id[$id] = $key;
|
||||
continue;
|
||||
}
|
||||
|
||||
$builtin_key = $panel->getBuiltinKey();
|
||||
if ($builtin_key) {
|
||||
$by_builtin[$builtin_key] = $key;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$key_order = array();
|
||||
foreach ($order as $order_item) {
|
||||
if (isset($by_id[$order_item])) {
|
||||
$key_order[] = $by_id[$order_item];
|
||||
continue;
|
||||
}
|
||||
if (isset($by_builtin[$order_item])) {
|
||||
$key_order[] = $by_builtin[$order_item];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$panels = array_select_keys($panels, $key_order) + $panels;
|
||||
|
||||
$type_order =
|
||||
PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER;
|
||||
|
||||
$order = 1;
|
||||
foreach ($panels as $panel) {
|
||||
$xactions = array();
|
||||
|
||||
$xactions[] = id(new PhabricatorProfilePanelConfigurationTransaction())
|
||||
->setTransactionType($type_order)
|
||||
->setNewValue($order);
|
||||
|
||||
$editor = id(new PhabricatorProfilePanelEditor())
|
||||
->setContentSourceFromRequest($request)
|
||||
->setActor($viewer)
|
||||
->setContinueOnMissingFields(true)
|
||||
->setContinueOnNoEffect(true)
|
||||
->applyTransactions($panel, $xactions);
|
||||
|
||||
$order++;
|
||||
}
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($this->getConfigureURI());
|
||||
}
|
||||
|
||||
|
||||
private function buildPanelConfigureContent(array $panels) {
|
||||
$viewer = $this->getViewer();
|
||||
$object = $this->getProfileObject();
|
||||
|
@ -314,7 +392,18 @@ final class PhabricatorProfilePanelEngine extends Phobject {
|
|||
$object,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$list = new PHUIObjectItemListView();
|
||||
$list_id = celerity_generate_unique_node_id();
|
||||
|
||||
Javelin::initBehavior(
|
||||
'reorder-profile-menu-items',
|
||||
array(
|
||||
'listID' => $list_id,
|
||||
'orderURI' => $this->getPanelURI('reorder/'),
|
||||
));
|
||||
|
||||
$list = id(new PHUIObjectItemListView())
|
||||
->setID($list_id);
|
||||
|
||||
foreach ($panels as $panel) {
|
||||
$id = $panel->getID();
|
||||
$builtin_key = $panel->getBuiltinKey();
|
||||
|
@ -336,6 +425,14 @@ final class PhabricatorProfilePanelEngine extends Phobject {
|
|||
$item->addAttribute($type);
|
||||
|
||||
if ($can_edit) {
|
||||
$item
|
||||
->setGrippable(true)
|
||||
->addSigil('profile-menu-item')
|
||||
->setMetadata(
|
||||
array(
|
||||
'key' => nonempty($id, $builtin_key),
|
||||
));
|
||||
|
||||
if ($id) {
|
||||
$item->setHref($this->getPanelURI("edit/{$id}/"));
|
||||
} else {
|
||||
|
|
|
@ -101,6 +101,20 @@ final class PhabricatorProfilePanelConfiguration
|
|||
return $this->getPanel()->getDisplayName($this);
|
||||
}
|
||||
|
||||
public function getSortKey() {
|
||||
$order = $this->getPanelOrder();
|
||||
if ($order === null) {
|
||||
$order = 'Z';
|
||||
} else {
|
||||
$order = sprintf('%020d', $order);
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'~%s%020d',
|
||||
$order,
|
||||
$this->getID());
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ final class PhabricatorProfilePanelConfigurationTransaction
|
|||
extends PhabricatorApplicationTransaction {
|
||||
|
||||
const TYPE_PROPERTY = 'profilepanel.property';
|
||||
const TYPE_ORDER = 'profilepanel.order';
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'search';
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* @provides javelin-behavior-reorder-profile-menu-items
|
||||
* @requires javelin-behavior
|
||||
* javelin-stratcom
|
||||
* javelin-workflow
|
||||
* javelin-dom
|
||||
* phabricator-draggable-list
|
||||
*/
|
||||
|
||||
JX.behavior('reorder-profile-menu-items', function(config) {
|
||||
|
||||
var root = JX.$(config.listID);
|
||||
|
||||
var list = new JX.DraggableList('profile-menu-item', root)
|
||||
.setFindItemsHandler(function() {
|
||||
return JX.DOM.scry(root, 'li', 'profile-menu-item');
|
||||
});
|
||||
|
||||
list.listen('didDrop', function(node) {
|
||||
var nodes = list.findItems();
|
||||
var order = [];
|
||||
var key;
|
||||
for (var ii = 0; ii < nodes.length; ii++) {
|
||||
key = JX.Stratcom.getData(nodes[ii]).key;
|
||||
if (key) {
|
||||
order.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
list.lock();
|
||||
JX.DOM.alterClass(node, 'drag-sending', true);
|
||||
|
||||
new JX.Workflow(config.orderURI, {order: order.join()})
|
||||
.setHandler(function() {
|
||||
JX.DOM.alterClass(node, 'drag-sending', false);
|
||||
list.unlock();
|
||||
})
|
||||
.start();
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in a new issue