mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 23:02:42 +01:00
Allow EditEngine create and edit forms to be reordered
Summary: Ref T9132. Ref T9908. Puts reordering UI in place: - For create forms, this just lets you pick a UI display order other than alphabetical. Seems nice to have. - For edit forms, this lets you create a hierarchy of advanced-to-basic forms and give them different visibility policies, if you want. Test Plan: {F1017842} - Verified that "Edit Thing" now takes me to the highest-ranked edit form. - Verified that create menu and quick create menu reflect application order. Reviewers: chad Reviewed By: chad Maniphest Tasks: T9132, T9908 Differential Revision: https://secure.phabricator.com/D14704
This commit is contained in:
parent
2f8e409876
commit
59ae0d6fff
11 changed files with 309 additions and 5 deletions
|
@ -428,6 +428,7 @@ return array(
|
|||
'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' => '6de53e91',
|
||||
'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' => 'dbbf48b6',
|
||||
'rsrc/js/application/transactions/behavior-transaction-comment-form.js' => 'b23b49e6',
|
||||
|
@ -604,6 +605,7 @@ return array(
|
|||
'javelin-behavior-doorkeeper-tag' => 'e5822781',
|
||||
'javelin-behavior-drydock-live-operation-status' => '901935ef',
|
||||
'javelin-behavior-durable-column' => 'c72aa091',
|
||||
'javelin-behavior-editengine-reorder-configs' => 'd7a74243',
|
||||
'javelin-behavior-editengine-reorder-fields' => 'b59e1e96',
|
||||
'javelin-behavior-error-log' => '6882e80a',
|
||||
'javelin-behavior-event-all-day' => '38dcf3c8',
|
||||
|
@ -1867,6 +1869,13 @@ return array(
|
|||
'javelin-dom',
|
||||
'phabricator-keyboard-shortcut',
|
||||
),
|
||||
'd7a74243' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
'javelin-dom',
|
||||
'phabricator-draggable-list',
|
||||
),
|
||||
'd835b03a' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
|
|
@ -2143,6 +2143,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorEditEngineConfigurationReorderController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationReorderController.php',
|
||||
'PhabricatorEditEngineConfigurationSaveController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationSaveController.php',
|
||||
'PhabricatorEditEngineConfigurationSearchEngine' => 'applications/transactions/query/PhabricatorEditEngineConfigurationSearchEngine.php',
|
||||
'PhabricatorEditEngineConfigurationSortController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationSortController.php',
|
||||
'PhabricatorEditEngineConfigurationTransaction' => 'applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php',
|
||||
'PhabricatorEditEngineConfigurationTransactionQuery' => 'applications/transactions/query/PhabricatorEditEngineConfigurationTransactionQuery.php',
|
||||
'PhabricatorEditEngineConfigurationViewController' => 'applications/transactions/controller/PhabricatorEditEngineConfigurationViewController.php',
|
||||
|
@ -6272,6 +6273,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorEditEngineConfigurationReorderController' => 'PhabricatorEditEngineController',
|
||||
'PhabricatorEditEngineConfigurationSaveController' => 'PhabricatorEditEngineController',
|
||||
'PhabricatorEditEngineConfigurationSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'PhabricatorEditEngineConfigurationSortController' => 'PhabricatorEditEngineController',
|
||||
'PhabricatorEditEngineConfigurationTransaction' => 'PhabricatorApplicationTransaction',
|
||||
'PhabricatorEditEngineConfigurationTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorEditEngineConfigurationViewController' => 'PhabricatorEditEngineController',
|
||||
|
|
|
@ -24,6 +24,7 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
|||
private $context;
|
||||
private $controller;
|
||||
private $namedQueries;
|
||||
private $navigationItems = array();
|
||||
|
||||
const CONTEXT_LIST = 'list';
|
||||
const CONTEXT_PANEL = 'panel';
|
||||
|
@ -86,6 +87,18 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
|||
return ($this->context == self::CONTEXT_PANEL);
|
||||
}
|
||||
|
||||
public function setNavigationItems(array $navigation_items) {
|
||||
assert_instances_of($navigation_items, 'PHUIListItemView');
|
||||
$this->navigationItems = $navigation_items;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getNavigationItems() {
|
||||
return $this->navigationItems;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function canUseInPanelContext() {
|
||||
return true;
|
||||
}
|
||||
|
@ -476,6 +489,10 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
|||
$advanced_uri = $this->getQueryResultsPageURI('advanced');
|
||||
$menu->newLink(pht('Advanced Search'), $advanced_uri, 'query/advanced');
|
||||
|
||||
foreach ($this->navigationItems as $extra_item) {
|
||||
$menu->addMenuItem($extra_item);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,8 @@ final class PhabricatorTransactionsApplication extends PhabricatorApplication {
|
|||
'PhabricatorEditEngineConfigurationListController',
|
||||
$this->getEditRoutePattern('edit/') =>
|
||||
'PhabricatorEditEngineConfigurationEditController',
|
||||
'sort/(?P<type>edit|create)/' =>
|
||||
'PhabricatorEditEngineConfigurationSortController',
|
||||
'view/(?P<key>[^/]+)/' =>
|
||||
'PhabricatorEditEngineConfigurationViewController',
|
||||
'save/(?P<key>[^/]+)/' =>
|
||||
|
|
|
@ -8,11 +8,44 @@ final class PhabricatorEditEngineConfigurationListController
|
|||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$this->setEngineKey($request->getURIData('engineKey'));
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$engine_key = $request->getURIData('engineKey');
|
||||
$this->setEngineKey($engine_key);
|
||||
|
||||
$engine = PhabricatorEditEngine::getByKey($viewer, $engine_key);
|
||||
|
||||
$items = array();
|
||||
$items[] = id(new PHUIListItemView())
|
||||
->setType(PHUIListItemView::TYPE_LABEL)
|
||||
->setName(pht('Form Order'));
|
||||
|
||||
$sort_create_uri = "/transactions/editengine/{$engine_key}/sort/create/";
|
||||
$sort_edit_uri = "/transactions/editengine/{$engine_key}/sort/edit/";
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$engine,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$items[] = id(new PHUIListItemView())
|
||||
->setType(PHUIListItemView::TYPE_LINK)
|
||||
->setName(pht('Reorder Create Forms'))
|
||||
->setHref($sort_create_uri)
|
||||
->setWorkflow(true)
|
||||
->setDisabled(!$can_edit);
|
||||
|
||||
$items[] = id(new PHUIListItemView())
|
||||
->setType(PHUIListItemView::TYPE_LINK)
|
||||
->setName(pht('Reorder Edit Forms'))
|
||||
->setHref($sort_edit_uri)
|
||||
->setWorkflow(true)
|
||||
->setDisabled(!$can_edit);
|
||||
|
||||
return id(new PhabricatorEditEngineConfigurationSearchEngine())
|
||||
->setController($this)
|
||||
->setEngineKey($this->getEngineKey())
|
||||
->setNavigationItems($items)
|
||||
->buildResponse();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorEditEngineConfigurationSortController
|
||||
extends PhabricatorEditEngineController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
$engine_key = $request->getURIData('engineKey');
|
||||
$this->setEngineKey($engine_key);
|
||||
|
||||
$type = $request->getURIData('type');
|
||||
$is_create = ($type == 'create');
|
||||
|
||||
$engine = id(new PhabricatorEditEngineQuery())
|
||||
->setViewer($viewer)
|
||||
->withEngineKeys(array($engine_key))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$engine) {
|
||||
return id(new Aphront404Response());
|
||||
}
|
||||
|
||||
$cancel_uri = "/transactions/editengine/{$engine_key}/";
|
||||
$reorder_uri = "/transactions/editengine/{$engine_key}/sort/{$type}/";
|
||||
|
||||
$query = id(new PhabricatorEditEngineConfigurationQuery())
|
||||
->setViewer($viewer)
|
||||
->withEngineKeys(array($engine->getEngineKey()));
|
||||
|
||||
if ($is_create) {
|
||||
$query->withIsDefault(true);
|
||||
} else {
|
||||
$query->withIsEdit(true);
|
||||
}
|
||||
|
||||
$configs = $query->execute();
|
||||
|
||||
if ($is_create) {
|
||||
$configs = msort($configs, 'getCreateSortKey');
|
||||
} else {
|
||||
$configs = msort($configs, 'getEditSortKey');
|
||||
}
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$form_order = $request->getStrList('formOrder');
|
||||
|
||||
// NOTE: This has a side-effect of saving any factory-default forms
|
||||
// to the database. We might want to warn the user better, but this
|
||||
// shouldn't generally be very important or confusing.
|
||||
|
||||
$configs = mpull($configs, null, 'getIdentifier');
|
||||
$configs = array_select_keys($configs, $form_order) + $configs;
|
||||
|
||||
$order = 1;
|
||||
foreach ($configs as $config) {
|
||||
$xactions = array();
|
||||
|
||||
if ($is_create) {
|
||||
$xaction_type =
|
||||
PhabricatorEditEngineConfigurationTransaction::TYPE_CREATEORDER;
|
||||
} else {
|
||||
$xaction_type =
|
||||
PhabricatorEditEngineConfigurationTransaction::TYPE_EDITORDER;
|
||||
}
|
||||
|
||||
$xactions[] = id(new PhabricatorEditEngineConfigurationTransaction())
|
||||
->setTransactionType($xaction_type)
|
||||
->setNewValue($order);
|
||||
|
||||
$editor = id(new PhabricatorEditEngineConfigurationEditor())
|
||||
->setActor($viewer)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setContinueOnNoEffect(true);
|
||||
|
||||
$editor->applyTransactions($config, $xactions);
|
||||
|
||||
$order++;
|
||||
}
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($cancel_uri);
|
||||
}
|
||||
|
||||
$list_id = celerity_generate_unique_node_id();
|
||||
$input_id = celerity_generate_unique_node_id();
|
||||
|
||||
$list = id(new PHUIObjectItemListView())
|
||||
->setUser($viewer)
|
||||
->setID($list_id)
|
||||
->setFlush(true);
|
||||
|
||||
$form_order = array();
|
||||
foreach ($configs as $config) {
|
||||
$name = $config->getName();
|
||||
$identifier = $config->getIdentifier();
|
||||
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setHeader($name)
|
||||
->setGrippable(true)
|
||||
->addSigil('editengine-form-config')
|
||||
->setMetadata(
|
||||
array(
|
||||
'formIdentifier' => $identifier,
|
||||
));
|
||||
|
||||
$list->addItem($item);
|
||||
|
||||
$form_order[] = $identifier;
|
||||
}
|
||||
|
||||
Javelin::initBehavior(
|
||||
'editengine-reorder-configs',
|
||||
array(
|
||||
'listID' => $list_id,
|
||||
'inputID' => $input_id,
|
||||
'reorderURI' => $reorder_uri,
|
||||
));
|
||||
|
||||
if ($is_create) {
|
||||
$title = pht('Reorder Create Forms');
|
||||
$button = pht('Save Create Order');
|
||||
|
||||
$note_text = pht(
|
||||
'Drag and drop fields to change the order in which they appear in '.
|
||||
'the application "Create" menu.');
|
||||
} else {
|
||||
$title = pht('Reorder Edit Forms');
|
||||
$button = pht('Save Edit Order');
|
||||
|
||||
$note_text = pht(
|
||||
'Drag and drop fields to change their priority for edits. When a '.
|
||||
'user edits an object, they will be shown the first form in this '.
|
||||
'list that they have permission to see.');
|
||||
}
|
||||
|
||||
$note = id(new PHUIInfoView())
|
||||
->appendChild($note_text)
|
||||
->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
|
||||
|
||||
$input = phutil_tag(
|
||||
'input',
|
||||
array(
|
||||
'type' => 'hidden',
|
||||
'name' => 'formOrder',
|
||||
'value' => implode(', ', $form_order),
|
||||
'id' => $input_id,
|
||||
));
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle($title)
|
||||
->setWidth(AphrontDialogView::WIDTH_FORM)
|
||||
->appendChild($note)
|
||||
->appendChild($list)
|
||||
->appendChild($input)
|
||||
->addSubmitButton(pht('Save Changes'))
|
||||
->addCancelButton($cancel_uri);
|
||||
}
|
||||
|
||||
}
|
|
@ -1031,8 +1031,6 @@ abstract class PhabricatorEditEngine
|
|||
$create_uri = $this->getEditURI(null, "form/{$form_key}/");
|
||||
|
||||
if (count($configs) > 1) {
|
||||
$configs = msort($configs, 'getDisplayName');
|
||||
|
||||
$menu_icon = 'fa-caret-square-o-down';
|
||||
|
||||
$dropdown = id(new PhabricatorActionListView())
|
||||
|
@ -1068,7 +1066,14 @@ abstract class PhabricatorEditEngine
|
|||
}
|
||||
|
||||
final public function buildEditEngineCommentView($object) {
|
||||
$config = $this->loadDefaultConfiguration();
|
||||
$config = $this->loadDefaultEditConfiguration();
|
||||
|
||||
if (!$config) {
|
||||
// TODO: This just nukes the entire comment form if you don't have access
|
||||
// to any edit forms. We might want to tailor this UX a bit.
|
||||
return id(new PhabricatorApplicationTransactionCommentView())
|
||||
->setNoPermission(true);
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$object_phid = $object->getPHID();
|
||||
|
@ -1260,7 +1265,11 @@ abstract class PhabricatorEditEngine
|
|||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
$config = $this->loadDefaultConfiguration();
|
||||
$config = $this->loadDefaultEditConfiguration();
|
||||
if (!$config) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$fields = $this->buildEditFields($object);
|
||||
|
||||
$is_preview = $request->isPreviewRequest();
|
||||
|
|
|
@ -26,6 +26,8 @@ final class PhabricatorEditEngineConfigurationEditor
|
|||
$types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_ISEDIT;
|
||||
$types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_DISABLE;
|
||||
|
||||
$types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_CREATEORDER;
|
||||
$types[] = PhabricatorEditEngineConfigurationTransaction::TYPE_EDITORDER;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
@ -80,6 +82,10 @@ final class PhabricatorEditEngineConfigurationEditor
|
|||
return (int)$object->getIsEdit();
|
||||
case PhabricatorEditEngineConfigurationTransaction::TYPE_DISABLE:
|
||||
return (int)$object->getIsDisabled();
|
||||
case PhabricatorEditEngineConfigurationTransaction::TYPE_CREATEORDER:
|
||||
return (int)$object->getCreateOrder();
|
||||
case PhabricatorEditEngineConfigurationTransaction::TYPE_EDITORDER:
|
||||
return (int)$object->getEditOrder();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,6 +103,8 @@ final class PhabricatorEditEngineConfigurationEditor
|
|||
case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE:
|
||||
case PhabricatorEditEngineConfigurationTransaction::TYPE_ISEDIT:
|
||||
case PhabricatorEditEngineConfigurationTransaction::TYPE_DISABLE:
|
||||
case PhabricatorEditEngineConfigurationTransaction::TYPE_CREATEORDER:
|
||||
case PhabricatorEditEngineConfigurationTransaction::TYPE_EDITORDER:
|
||||
return (int)$xaction->getNewValue();
|
||||
}
|
||||
}
|
||||
|
@ -131,6 +139,12 @@ final class PhabricatorEditEngineConfigurationEditor
|
|||
case PhabricatorEditEngineConfigurationTransaction::TYPE_DISABLE:
|
||||
$object->setIsDisabled($xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorEditEngineConfigurationTransaction::TYPE_CREATEORDER:
|
||||
$object->setCreateOrder($xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorEditEngineConfigurationTransaction::TYPE_EDITORDER:
|
||||
$object->setEditOrder($xaction->getNewValue());
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::applyCustomInternalTransaction($object, $xaction);
|
||||
|
@ -149,6 +163,8 @@ final class PhabricatorEditEngineConfigurationEditor
|
|||
case PhabricatorEditEngineConfigurationTransaction::TYPE_LOCKS:
|
||||
case PhabricatorEditEngineConfigurationTransaction::TYPE_DEFAULTCREATE:
|
||||
case PhabricatorEditEngineConfigurationTransaction::TYPE_DISABLE:
|
||||
case PhabricatorEditEngineConfigurationTransaction::TYPE_CREATEORDER:
|
||||
case PhabricatorEditEngineConfigurationTransaction::TYPE_EDITORDER:
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ final class PhabricatorEditEngineConfigurationTransaction
|
|||
const TYPE_DEFAULTCREATE = 'editengine.config.default.create';
|
||||
const TYPE_ISEDIT = 'editengine.config.isedit';
|
||||
const TYPE_DISABLE = 'editengine.config.disable';
|
||||
const TYPE_CREATEORDER = 'editengine.order.create';
|
||||
const TYPE_EDITORDER = 'editengine.order.edit';
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'search';
|
||||
|
|
|
@ -18,6 +18,9 @@ class PhabricatorApplicationTransactionCommentView extends AphrontView {
|
|||
private $showPreview = true;
|
||||
private $objectPHID;
|
||||
private $headerText;
|
||||
private $noPermission;
|
||||
|
||||
|
||||
|
||||
private $currentVersion;
|
||||
private $versionedDraft;
|
||||
|
@ -110,16 +113,32 @@ class PhabricatorApplicationTransactionCommentView extends AphrontView {
|
|||
return $this->editTypes;
|
||||
}
|
||||
|
||||
public function setNoPermission($no_permission) {
|
||||
$this->noPermission = $no_permission;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getNoPermission() {
|
||||
return $this->noPermission;
|
||||
}
|
||||
|
||||
public function setTransactionTimeline(
|
||||
PhabricatorApplicationTransactionView $timeline) {
|
||||
|
||||
$timeline->setQuoteTargetID($this->getCommentID());
|
||||
if ($this->getNoPermission()) {
|
||||
$timeline->setShouldTerminate(true);
|
||||
}
|
||||
|
||||
$this->transactionTimeline = $timeline;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
if ($this->getNoPermission()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$user = $this->getUser();
|
||||
if (!$user->isLoggedIn()) {
|
||||
$uri = id(new PhutilURI('/login/'))
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* @provides javelin-behavior-editengine-reorder-configs
|
||||
* @requires javelin-behavior
|
||||
* javelin-stratcom
|
||||
* javelin-workflow
|
||||
* javelin-dom
|
||||
* phabricator-draggable-list
|
||||
*/
|
||||
|
||||
JX.behavior('editengine-reorder-configs', function(config) {
|
||||
|
||||
var root = JX.$(config.listID);
|
||||
|
||||
var list = new JX.DraggableList('editengine-form-config', root)
|
||||
.setFindItemsHandler(function() {
|
||||
return JX.DOM.scry(root, 'li', 'editengine-form-config');
|
||||
});
|
||||
|
||||
list.listen('didDrop', function() {
|
||||
var nodes = list.findItems();
|
||||
|
||||
var data;
|
||||
var keys = [];
|
||||
for (var ii = 0; ii < nodes.length; ii++) {
|
||||
data = JX.Stratcom.getData(nodes[ii]);
|
||||
keys.push(data.formIdentifier);
|
||||
}
|
||||
|
||||
JX.$(config.inputID).value = keys.join(',');
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in a new issue