diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -476,7 +476,7 @@ 'rsrc/js/core/behavior-audio-source.js' => '59b251eb', 'rsrc/js/core/behavior-autofocus.js' => '7319e029', 'rsrc/js/core/behavior-badge-view.js' => '8ff5e24c', - 'rsrc/js/core/behavior-bulk-editor.js' => '5e178556', + 'rsrc/js/core/behavior-bulk-editor.js' => '66a6def1', 'rsrc/js/core/behavior-choose-control.js' => '327a00d1', 'rsrc/js/core/behavior-copy.js' => 'b0b8f86d', 'rsrc/js/core/behavior-detect-timezone.js' => '4c193c96', @@ -595,7 +595,7 @@ 'javelin-behavior-audio-source' => '59b251eb', 'javelin-behavior-audit-preview' => 'd835b03a', 'javelin-behavior-badge-view' => '8ff5e24c', - 'javelin-behavior-bulk-editor' => '5e178556', + 'javelin-behavior-bulk-editor' => '66a6def1', 'javelin-behavior-bulk-job-reload' => 'edf8a145', 'javelin-behavior-calendar-month-view' => 'fe33e256', 'javelin-behavior-choose-control' => '327a00d1', @@ -1391,15 +1391,6 @@ 'javelin-stratcom', 'javelin-dom', ), - '5e178556' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-util', - 'phabricator-prefab', - 'multirow-row-manager', - 'javelin-json', - 'phuix-form-control-view', - ), '5e2634b9' => array( 'javelin-behavior', 'javelin-aphlict', @@ -1436,6 +1427,14 @@ 'javelin-workflow', 'javelin-dom', ), + '66a6def1' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-util', + 'multirow-row-manager', + 'javelin-json', + 'phuix-form-control-view', + ), '680ea2c8' => array( 'javelin-install', 'javelin-dom', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2203,6 +2203,7 @@ 'PhabricatorBuiltinFileCachePurger' => 'applications/cache/purger/PhabricatorBuiltinFileCachePurger.php', 'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php', 'PhabricatorBulkContentSource' => 'infrastructure/daemon/contentsource/PhabricatorBulkContentSource.php', + 'PhabricatorBulkEditGroup' => 'applications/transactions/bulk/PhabricatorBulkEditGroup.php', 'PhabricatorBulkEngine' => 'applications/transactions/bulk/PhabricatorBulkEngine.php', 'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php', 'PhabricatorCacheEngine' => 'applications/system/engine/PhabricatorCacheEngine.php', @@ -7499,6 +7500,7 @@ 'PhabricatorBuiltinFileCachePurger' => 'PhabricatorCachePurger', 'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList', 'PhabricatorBulkContentSource' => 'PhabricatorContentSource', + 'PhabricatorBulkEditGroup' => 'Phobject', 'PhabricatorBulkEngine' => 'Phobject', 'PhabricatorCacheDAO' => 'PhabricatorLiskDAO', 'PhabricatorCacheEngine' => 'Phobject', diff --git a/src/applications/maniphest/view/ManiphestTaskResultListView.php b/src/applications/maniphest/view/ManiphestTaskResultListView.php --- a/src/applications/maniphest/view/ManiphestTaskResultListView.php +++ b/src/applications/maniphest/view/ManiphestTaskResultListView.php @@ -218,7 +218,7 @@ 'disabled' => 'disabled', 'class' => 'disabled', ), - pht("Batch Edit Selected \xC2\xBB")); + pht("Bulk Edit Selected \xC2\xBB")); $export = javelin_tag( 'a', diff --git a/src/applications/transactions/bulk/PhabricatorBulkEditGroup.php b/src/applications/transactions/bulk/PhabricatorBulkEditGroup.php new file mode 100644 --- /dev/null +++ b/src/applications/transactions/bulk/PhabricatorBulkEditGroup.php @@ -0,0 +1,27 @@ +key = $key; + return $this; + } + + public function getKey() { + return $this->key; + } + + public function setLabel($label) { + $this->label = $label; + return $this; + } + + public function getLabel() { + return $this->label; + } + +} diff --git a/src/applications/transactions/bulk/PhabricatorBulkEngine.php b/src/applications/transactions/bulk/PhabricatorBulkEngine.php --- a/src/applications/transactions/bulk/PhabricatorBulkEngine.php +++ b/src/applications/transactions/bulk/PhabricatorBulkEngine.php @@ -299,6 +299,29 @@ ->setViewer($viewer); $edit_map = $edit_engine->newBulkEditMap(); + $groups = $edit_engine->newBulkEditGroupMap(); + + $spec = array(); + $option_groups = igroup($edit_map, 'group'); + foreach ($groups as $group_key => $group) { + $options = idx($option_groups, $group_key, array()); + if (!$options) { + continue; + } + + $option_map = array(); + foreach ($options as $option) { + $option_map[] = array( + 'key' => $option['xaction'], + 'label' => $option['label'], + ); + } + + $spec[] = array( + 'label' => $group->getLabel(), + 'options' => $option_map, + ); + } require_celerity_resource('phui-bulk-editor-css'); @@ -308,6 +331,9 @@ 'rootNodeID' => $this->getRootFormID(), 'inputNodeID' => $input_id, 'edits' => $edit_map, + 'optgroups' => array( + 'groups' => $spec, + ), )); $cancel_uri = $this->getCancelURI(); diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php --- a/src/applications/transactions/editengine/PhabricatorEditEngine.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php @@ -181,6 +181,11 @@ $field ->setViewer($viewer) ->setObject($object); + + $group_key = $field->getBulkEditGroupKey(); + if ($group_key === null) { + $field->setBulkEditGroupKey('extension'); + } } $extension_fields = mpull($extension_fields, null, 'getKey'); @@ -2424,6 +2429,60 @@ /* -( Bulk Edits )--------------------------------------------------------- */ + final public function newBulkEditGroupMap() { + $groups = $this->newBulkEditGroups(); + + $map = array(); + foreach ($groups as $group) { + $key = $group->getKey(); + + if (isset($map[$key])) { + throw new Exception( + pht( + 'Two bulk edit groups have the same key ("%s"). Each bulk edit '. + 'group must have a unique key.', + $key)); + } + + $map[$key] = $group; + } + + if ($this->isEngineExtensible()) { + $extensions = PhabricatorEditEngineExtension::getAllEnabledExtensions(); + } else { + $extensions = array(); + } + + foreach ($extensions as $extension) { + $extension_groups = $extension->newBulkEditGroups($this); + foreach ($extension_groups as $group) { + $key = $group->getKey(); + + if (isset($map[$key])) { + throw new Exception( + pht( + 'Extension "%s" defines a bulk edit group with the same key '. + '("%s") as the main editor or another extension. Each bulk '. + 'edit group must have a unique key.')); + } + + $map[$key] = $group; + } + } + + return $map; + } + + protected function newBulkEditGroups() { + return array( + id(new PhabricatorBulkEditGroup()) + ->setKey('default') + ->setLabel(pht('Primary Fields')), + id(new PhabricatorBulkEditGroup()) + ->setKey('extension') + ->setLabel(pht('Support Applications')), + ); + } final public function newBulkEditMap() { $config = $this->loadDefaultConfiguration(); @@ -2434,6 +2493,7 @@ $object = $this->newEditableObject(); $fields = $this->buildEditFields($object); + $groups = $this->newBulkEditGroupMap(); $edit_types = $this->getBulkEditTypesFromFields($fields); @@ -2449,9 +2509,24 @@ continue; } + $group_key = $type->getBulkEditGroupKey(); + if (!$group_key) { + $group_key = 'default'; + } + + if (!isset($groups[$group_key])) { + throw new Exception( + pht( + 'Field "%s" has a bulk edit group key ("%s") with no '. + 'corresponding bulk edit group.', + $key, + $group_key)); + } + $map[] = array( 'label' => $bulk_label, 'xaction' => $key, + 'group' => $group_key, 'control' => array( 'type' => $bulk_type->getPHUIXControlType(), 'spec' => (object)$bulk_type->getPHUIXControlSpecification(), diff --git a/src/applications/transactions/editfield/PhabricatorEditField.php b/src/applications/transactions/editfield/PhabricatorEditField.php --- a/src/applications/transactions/editfield/PhabricatorEditField.php +++ b/src/applications/transactions/editfield/PhabricatorEditField.php @@ -18,6 +18,7 @@ private $controlID; private $controlInstructions; private $bulkEditLabel; + private $bulkEditGroupKey; private $description; private $conduitDescription; @@ -75,6 +76,15 @@ return $this->bulkEditLabel; } + public function setBulkEditGroupKey($key) { + $this->bulkEditGroupKey = $key; + return $this; + } + + public function getBulkEditGroupKey() { + return $this->bulkEditGroupKey; + } + public function setViewer(PhabricatorUser $viewer) { $this->viewer = $viewer; return $this; diff --git a/src/applications/transactions/edittype/PhabricatorEditType.php b/src/applications/transactions/edittype/PhabricatorEditType.php --- a/src/applications/transactions/edittype/PhabricatorEditType.php +++ b/src/applications/transactions/edittype/PhabricatorEditType.php @@ -15,6 +15,7 @@ private $bulkParameterType; private $bulkEditLabel; + private $bulkEditGroupKey; public function setLabel($label) { $this->label = $label; @@ -38,6 +39,19 @@ return $this->getEditField()->getBulkEditLabel(); } + public function setBulkEditGroupKey($key) { + $this->bulkEditGroupKey = $key; + return $this; + } + + public function getBulkEditGroupKey() { + if ($this->bulkEditGroupKey !== null) { + return $this->bulkEditGroupKey; + } + + return $this->getEditField()->getBulkEditGroupKey(); + } + public function setEditType($edit_type) { $this->editType = $edit_type; return $this; diff --git a/src/applications/transactions/engineextension/PhabricatorCommentEditEngineExtension.php b/src/applications/transactions/engineextension/PhabricatorCommentEditEngineExtension.php --- a/src/applications/transactions/engineextension/PhabricatorCommentEditEngineExtension.php +++ b/src/applications/transactions/engineextension/PhabricatorCommentEditEngineExtension.php @@ -33,6 +33,14 @@ return (bool)$comment; } + public function newBulkEditGroups(PhabricatorEditEngine $engine) { + return array( + id(new PhabricatorBulkEditGroup()) + ->setKey('comments') + ->setLabel(pht('Comments')), + ); + } + public function buildCustomEditFields( PhabricatorEditEngine $engine, PhabricatorApplicationTransactionInterface $object) { @@ -47,6 +55,7 @@ ->setKey(self::EDITKEY) ->setLabel(pht('Comments')) ->setBulkEditLabel(pht('Add comment')) + ->setBulkEditGroupKey('comments') ->setAliases(array('comments')) ->setIsHidden(true) ->setIsReorderable(false) diff --git a/src/applications/transactions/engineextension/PhabricatorEditEngineExtension.php b/src/applications/transactions/engineextension/PhabricatorEditEngineExtension.php --- a/src/applications/transactions/engineextension/PhabricatorEditEngineExtension.php +++ b/src/applications/transactions/engineextension/PhabricatorEditEngineExtension.php @@ -32,6 +32,10 @@ PhabricatorEditEngine $engine, PhabricatorApplicationTransactionInterface $object); + public function newBulkEditGroups(PhabricatorEditEngine $engine) { + return array(); + } + final public static function getAllExtensions() { return id(new PhutilClassMapQuery()) ->setAncestorClass(__CLASS__) diff --git a/src/infrastructure/customfield/engineextension/PhabricatorCustomFieldEditEngineExtension.php b/src/infrastructure/customfield/engineextension/PhabricatorCustomFieldEditEngineExtension.php --- a/src/infrastructure/customfield/engineextension/PhabricatorCustomFieldEditEngineExtension.php +++ b/src/infrastructure/customfield/engineextension/PhabricatorCustomFieldEditEngineExtension.php @@ -23,6 +23,14 @@ return ($object instanceof PhabricatorCustomFieldInterface); } + public function newBulkEditGroups(PhabricatorEditEngine $engine) { + return array( + id(new PhabricatorBulkEditGroup()) + ->setKey('custom') + ->setLabel(pht('Custom Fields')), + ); + } + public function buildCustomEditFields( PhabricatorEditEngine $engine, PhabricatorApplicationTransactionInterface $object) { @@ -43,6 +51,11 @@ foreach ($field_list->getFields() as $field) { $edit_fields = $field->getEditEngineFields($engine); foreach ($edit_fields as $edit_field) { + $group_key = $edit_field->getBulkEditGroupKey(); + if ($group_key === null) { + $edit_field->setBulkEditGroupKey('custom'); + } + $results[] = $edit_field; } } diff --git a/webroot/rsrc/js/core/behavior-bulk-editor.js b/webroot/rsrc/js/core/behavior-bulk-editor.js --- a/webroot/rsrc/js/core/behavior-bulk-editor.js +++ b/webroot/rsrc/js/core/behavior-bulk-editor.js @@ -3,7 +3,6 @@ * @requires javelin-behavior * javelin-dom * javelin-util - * phabricator-prefab * multirow-row-manager * javelin-json * phuix-form-control-view @@ -31,11 +30,9 @@ } function renderRow() { - var action_select = JX.Prefab.renderSelect( - option_map, - null, - null, - option_order); + var action_select = new JX.PHUIXFormControl() + .setControl('optgroups', config.optgroups) + .getRawInputNode(); var cell = JX.$N('td', {className: 'bulk-edit-input'}); var vfunc = null;