Page MenuHomePhabricator

D18863.diff
No OneTemporary

D18863.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -81,7 +81,6 @@
'rsrc/css/application/harbormaster/harbormaster.css' => 'f491c9f4',
'rsrc/css/application/herald/herald-test.css' => 'a52e323e',
'rsrc/css/application/herald/herald.css' => 'cd8d0134',
- 'rsrc/css/application/maniphest/batch-editor.css' => 'b0f0b6d5',
'rsrc/css/application/maniphest/report.css' => '9b9580b7',
'rsrc/css/application/maniphest/task-edit.css' => 'fda62a9b',
'rsrc/css/application/maniphest/task-summary.css' => '11cc5344',
@@ -143,6 +142,7 @@
'rsrc/css/phui/phui-basic-nav-view.css' => '98c11ab3',
'rsrc/css/phui/phui-big-info-view.css' => 'acc3492c',
'rsrc/css/phui/phui-box.css' => '4bd6cdb9',
+ 'rsrc/css/phui/phui-bulk-editor.css' => '1fe728a8',
'rsrc/css/phui/phui-chart.css' => '6bf6f78e',
'rsrc/css/phui/phui-cms.css' => '504b4b23',
'rsrc/css/phui/phui-comment-form.css' => 'ac68149f',
@@ -419,7 +419,6 @@
'rsrc/js/application/herald/HeraldRuleEditor.js' => '2dff5579',
'rsrc/js/application/herald/PathTypeahead.js' => 'f7fc67ec',
'rsrc/js/application/herald/herald-rule-editor.js' => '7ebaeed3',
- 'rsrc/js/application/maniphest/behavior-batch-editor.js' => '782ab6e7',
'rsrc/js/application/maniphest/behavior-batch-selector.js' => 'ad54037e',
'rsrc/js/application/maniphest/behavior-line-chart.js' => 'e4232876',
'rsrc/js/application/maniphest/behavior-list-edit.js' => 'a9f88de2',
@@ -477,6 +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-choose-control.js' => '327a00d1',
'rsrc/js/core/behavior-copy.js' => 'b0b8f86d',
'rsrc/js/core/behavior-detect-timezone.js' => '4c193c96',
@@ -532,7 +532,7 @@
'rsrc/js/phuix/PHUIXButtonView.js' => '8a91e1ac',
'rsrc/js/phuix/PHUIXDropdownMenu.js' => '04b2ae03',
'rsrc/js/phuix/PHUIXExample.js' => '68af71ca',
- 'rsrc/js/phuix/PHUIXFormControl.js' => '83e03671',
+ 'rsrc/js/phuix/PHUIXFormControl.js' => '68bb05aa',
'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b',
),
'symbols' => array(
@@ -595,6 +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-job-reload' => 'edf8a145',
'javelin-behavior-calendar-month-view' => 'fe33e256',
'javelin-behavior-choose-control' => '327a00d1',
@@ -642,7 +643,6 @@
'javelin-behavior-lightbox-attachments' => '560f41da',
'javelin-behavior-line-chart' => 'e4232876',
'javelin-behavior-load-blame' => '42126667',
- 'javelin-behavior-maniphest-batch-editor' => '782ab6e7',
'javelin-behavior-maniphest-batch-selector' => 'ad54037e',
'javelin-behavior-maniphest-list-editor' => 'a9f88de2',
'javelin-behavior-maniphest-subpriority-editor' => '71237763',
@@ -756,7 +756,6 @@
'javelin-workboard-column' => '758b4758',
'javelin-workboard-controller' => '26167537',
'javelin-workflow' => '1e911d0f',
- 'maniphest-batch-editor' => 'b0f0b6d5',
'maniphest-report-css' => '9b9580b7',
'maniphest-task-edit-css' => 'fda62a9b',
'maniphest-task-summary-css' => '11cc5344',
@@ -823,6 +822,7 @@
'phui-basic-nav-view-css' => '98c11ab3',
'phui-big-info-view-css' => 'acc3492c',
'phui-box-css' => '4bd6cdb9',
+ 'phui-bulk-editor-css' => '1fe728a8',
'phui-button-bar-css' => 'f1ff5494',
'phui-button-css' => '1863cc6e',
'phui-button-simple-css' => '8e1baf68',
@@ -884,7 +884,7 @@
'phuix-autocomplete' => 'e0731603',
'phuix-button-view' => '8a91e1ac',
'phuix-dropdown-menu' => '04b2ae03',
- 'phuix-form-control-view' => '83e03671',
+ 'phuix-form-control-view' => '68bb05aa',
'phuix-icon-view' => 'bff6884b',
'policy-css' => '957ea14c',
'policy-edit-css' => '815c66f7',
@@ -1387,6 +1387,15 @@
'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 +1445,10 @@
'javelin-dom',
'phuix-button-view',
),
+ '68bb05aa' => array(
+ 'javelin-install',
+ 'javelin-dom',
+ ),
'69adf288' => array(
'javelin-install',
),
@@ -1524,14 +1537,6 @@
'javelin-request',
'javelin-util',
),
- '782ab6e7' => array(
- 'javelin-behavior',
- 'javelin-dom',
- 'javelin-util',
- 'phabricator-prefab',
- 'multirow-row-manager',
- 'javelin-json',
- ),
'7927a7d3' => array(
'javelin-behavior',
'javelin-quicksand',
@@ -1570,10 +1575,6 @@
'javelin-behavior',
'javelin-scrollbar',
),
- '83e03671' => array(
- 'javelin-install',
- 'javelin-dom',
- ),
'8499b6ab' => array(
'javelin-behavior',
'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
@@ -222,6 +222,8 @@
'AuditConduitAPIMethod' => 'applications/audit/conduit/AuditConduitAPIMethod.php',
'AuditQueryConduitAPIMethod' => 'applications/audit/conduit/AuditQueryConduitAPIMethod.php',
'AuthManageProvidersCapability' => 'applications/auth/capability/AuthManageProvidersCapability.php',
+ 'BulkParameterType' => 'applications/transactions/bulk/type/BulkParameterType.php',
+ 'BulkStringParameterType' => 'applications/transactions/bulk/type/BulkStringParameterType.php',
'CalendarTimeUtil' => 'applications/calendar/util/CalendarTimeUtil.php',
'CalendarTimeUtilTestCase' => 'applications/calendar/__tests__/CalendarTimeUtilTestCase.php',
'CelerityAPI' => 'applications/celerity/CelerityAPI.php',
@@ -5242,6 +5244,8 @@
'AuditConduitAPIMethod' => 'ConduitAPIMethod',
'AuditQueryConduitAPIMethod' => 'AuditConduitAPIMethod',
'AuthManageProvidersCapability' => 'PhabricatorPolicyCapability',
+ 'BulkParameterType' => 'Phobject',
+ 'BulkStringParameterType' => 'BulkParameterType',
'CalendarTimeUtil' => 'Phobject',
'CalendarTimeUtilTestCase' => 'PhabricatorTestCase',
'CelerityAPI' => 'Phobject',
diff --git a/src/applications/maniphest/bulk/ManiphestTaskBulkEngine.php b/src/applications/maniphest/bulk/ManiphestTaskBulkEngine.php
--- a/src/applications/maniphest/bulk/ManiphestTaskBulkEngine.php
+++ b/src/applications/maniphest/bulk/ManiphestTaskBulkEngine.php
@@ -18,6 +18,10 @@
return new ManiphestTaskSearchEngine();
}
+ public function newEditEngine() {
+ return new ManiphestEditEngine();
+ }
+
public function getDoneURI() {
$board_uri = $this->getBoardURI();
if ($board_uri) {
diff --git a/src/applications/maniphest/editor/ManiphestEditEngine.php b/src/applications/maniphest/editor/ManiphestEditEngine.php
--- a/src/applications/maniphest/editor/ManiphestEditEngine.php
+++ b/src/applications/maniphest/editor/ManiphestEditEngine.php
@@ -178,6 +178,7 @@
id(new PhabricatorTextEditField())
->setKey('title')
->setLabel(pht('Title'))
+ ->setBulkEditLabel(pht('Set title to'))
->setDescription(pht('Name of the task.'))
->setConduitDescription(pht('Rename the task.'))
->setConduitTypeDescription(pht('New task name.'))
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
@@ -10,7 +10,10 @@
private $editableList;
private $targetList;
+ private $rootFormID;
+
abstract public function newSearchEngine();
+ abstract public function newEditEngine();
public function getCancelURI() {
$saved_query = $this->savedQuery;
@@ -118,7 +121,7 @@
array(
'action' => $this->getBulkURI(),
'method' => 'POST',
- 'id' => 'maniphest-batch-edit-form',
+ 'id' => $this->getRootFormID(),
),
array(
$this->newContextInputs(),
@@ -290,95 +293,60 @@
private function newBulkActionForm() {
$viewer = $this->getViewer();
+ $input_id = celerity_generate_unique_node_id();
- $cancel_uri = $this->getCancelURI();
-
- $template = new AphrontTokenizerTemplateView();
- $template = $template->render();
-
- $projects_source = new PhabricatorProjectDatasource();
- $mailable_source = new PhabricatorMetaMTAMailableDatasource();
- $mailable_source->setViewer($viewer);
- $owner_source = new ManiphestAssigneeDatasource();
- $owner_source->setViewer($viewer);
- $spaces_source = id(new PhabricatorSpacesNamespaceDatasource())
+ $edit_engine = id($this->newEditEngine())
->setViewer($viewer);
- require_celerity_resource('maniphest-batch-editor');
+ $edit_map = $edit_engine->newBulkEditMap();
+
+ require_celerity_resource('phui-bulk-editor-css');
Javelin::initBehavior(
- 'maniphest-batch-editor',
+ 'bulk-editor',
array(
- 'root' => 'maniphest-batch-edit-form',
- 'tokenizerTemplate' => $template,
- 'sources' => array(
- 'project' => array(
- 'src' => $projects_source->getDatasourceURI(),
- 'placeholder' => $projects_source->getPlaceholderText(),
- 'browseURI' => $projects_source->getBrowseURI(),
- ),
- 'owner' => array(
- 'src' => $owner_source->getDatasourceURI(),
- 'placeholder' => $owner_source->getPlaceholderText(),
- 'browseURI' => $owner_source->getBrowseURI(),
- 'limit' => 1,
- ),
- 'cc' => array(
- 'src' => $mailable_source->getDatasourceURI(),
- 'placeholder' => $mailable_source->getPlaceholderText(),
- 'browseURI' => $mailable_source->getBrowseURI(),
- ),
- 'spaces' => array(
- 'src' => $spaces_source->getDatasourceURI(),
- 'placeholder' => $spaces_source->getPlaceholderText(),
- 'browseURI' => $spaces_source->getBrowseURI(),
- 'limit' => 1,
- ),
- ),
- 'input' => 'batch-form-actions',
- 'priorityMap' => ManiphestTaskPriority::getTaskPriorityMap(),
- 'statusMap' => ManiphestTaskStatus::getTaskStatusMap(),
+ 'rootNodeID' => $this->getRootFormID(),
+ 'inputNodeID' => $input_id,
+ 'edits' => $edit_map,
));
- $form = id(new PHUIFormLayoutView())
- ->setUser($viewer);
+ $cancel_uri = $this->getCancelURI();
- $form->appendChild(
- phutil_tag(
- 'input',
- array(
- 'type' => 'hidden',
- 'name' => 'actions',
- 'id' => 'batch-form-actions',
- )));
-
- $form->appendChild(
- id(new PHUIFormInsetView())
- ->setTitle(pht('Bulk Edit Actions'))
- ->setRightButton(
- javelin_tag(
- 'a',
- array(
- 'href' => '#',
- 'class' => 'button button-green',
- 'sigil' => 'add-action',
- 'mustcapture' => true,
- ),
- pht('Add Another Action')))
- ->setContent(
- javelin_tag(
- 'table',
- array(
- 'sigil' => 'maniphest-batch-actions',
- 'class' => 'maniphest-batch-actions-table',
- ),
- '')))
+ return id(new PHUIFormLayoutView())
+ ->setViewer($viewer)
+ ->appendChild(
+ phutil_tag(
+ 'input',
+ array(
+ 'type' => 'hidden',
+ 'name' => 'xactions',
+ 'id' => $input_id,
+ )))
+ ->appendChild(
+ id(new PHUIFormInsetView())
+ ->setTitle(pht('Bulk Edit Actions'))
+ ->setRightButton(
+ javelin_tag(
+ 'a',
+ array(
+ 'href' => '#',
+ 'class' => 'button button-green',
+ 'sigil' => 'add-action',
+ 'mustcapture' => true,
+ ),
+ pht('Add Another Action')))
+ ->setContent(
+ javelin_tag(
+ 'table',
+ array(
+ 'sigil' => 'bulk-actions',
+ 'class' => 'bulk-edit-table',
+ ),
+ '')))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Apply Bulk Edit'))
->addCancelButton($cancel_uri));
-
- return $form;
}
private function buildEditResponse() {
@@ -405,31 +373,33 @@
'You have not selected any objects to edit.'));
}
- $raw_actions = $request->getStr('actions');
- if ($raw_actions) {
- $actions = phutil_json_decode($raw_actions);
+ $raw_xactions = $request->getStr('xactions');
+ if ($raw_xactions) {
+ $raw_xactions = phutil_json_decode($raw_xactions);
} else {
- $actions = array();
+ $raw_xactions = array();
}
- if (!$actions) {
+ if (!$raw_xactions) {
throw new Exception(
pht(
'You have not chosen any edits to apply.'));
}
+ $edit_engine = id($this->newEditEngine())
+ ->setViewer($viewer);
+
+ $xactions = $edit_engine->newRawBulkTransactions($raw_xactions);
+
$cancel_uri = $this->getCancelURI();
$done_uri = $this->getDoneURI();
$job = PhabricatorWorkerBulkJob::initializeNewJob(
$viewer,
- // TODO: This is a Maniphest-specific job type for now, but will become
- // a generic one so it gets to live here for now instead of in the task
- // specific BulkEngine subclass.
- new ManiphestTaskEditBulkJobType(),
+ new PhabricatorEditEngineBulkJobType(),
array(
- 'taskPHIDs' => mpull($objects, 'getPHID'),
- 'actions' => $actions,
+ 'objectPHIDs' => mpull($objects, 'getPHID'),
+ 'xactions' => $xactions,
'cancelURI' => $cancel_uri,
'doneURI' => $done_uri,
));
@@ -451,4 +421,12 @@
->setURI($job->getMonitorURI());
}
+ private function getRootFormID() {
+ if (!$this->rootFormID) {
+ $this->rootFormID = celerity_generate_unique_node_id();
+ }
+
+ return $this->rootFormID;
+ }
+
}
diff --git a/src/applications/transactions/bulk/type/BulkParameterType.php b/src/applications/transactions/bulk/type/BulkParameterType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/bulk/type/BulkParameterType.php
@@ -0,0 +1,24 @@
+<?php
+
+abstract class BulkParameterType extends Phobject {
+
+ private $viewer;
+
+ final public function setViewer(PhabricatorUser $viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
+ final public function getViewer() {
+ return $this->viewer;
+ }
+
+ abstract public function getPHUIXControlType();
+
+ public function getPHUIXControlSpecification() {
+ return array(
+ 'value' => null,
+ );
+ }
+
+}
diff --git a/src/applications/transactions/bulk/type/BulkStringParameterType.php b/src/applications/transactions/bulk/type/BulkStringParameterType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/bulk/type/BulkStringParameterType.php
@@ -0,0 +1,10 @@
+<?php
+
+final class BulkStringParameterType
+ extends BulkParameterType {
+
+ public function getPHUIXControlType() {
+ return 'text';
+ }
+
+}
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
@@ -2421,6 +2421,71 @@
}
+/* -( Bulk Edits )--------------------------------------------------------- */
+
+
+ final public function newBulkEditMap() {
+ $config = $this->loadDefaultConfiguration();
+ if (!$config) {
+ throw new Exception(
+ pht('No default edit engine configuration for bulk edit.'));
+ }
+
+ $object = $this->newEditableObject();
+ $fields = $this->buildEditFields($object);
+
+ $edit_types = $this->getBulkEditTypesFromFields($fields);
+
+ $map = array();
+ foreach ($edit_types as $key => $type) {
+ $bulk_type = $type->getBulkParameterType();
+ if ($bulk_type === null) {
+ continue;
+ }
+
+ $bulk_label = $type->getBulkEditLabel();
+ if ($bulk_label === null) {
+ continue;
+ }
+
+ $map[] = array(
+ 'label' => $bulk_label,
+ 'xaction' => $type->getTransactionType(),
+ 'control' => array(
+ 'type' => $bulk_type->getPHUIXControlType(),
+ 'spec' => (object)$bulk_type->getPHUIXControlSpecification(),
+ ),
+ );
+ }
+
+ return $map;
+ }
+
+
+ final public function newRawBulkTransactions(array $xactions) {
+ return $xactions;
+ }
+
+ private function getBulkEditTypesFromFields(array $fields) {
+ $types = array();
+
+ foreach ($fields as $field) {
+ $field_types = $field->getBulkEditTypes();
+
+ if ($field_types === null) {
+ continue;
+ }
+
+ foreach ($field_types as $field_type) {
+ $field_type->setField($field);
+ $types[$field_type->getEditType()] = $field_type;
+ }
+ }
+
+ return $types;
+ }
+
+
/* -( PhabricatorPolicyInterface )----------------------------------------- */
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
@@ -17,6 +17,7 @@
private $previewPanel;
private $controlID;
private $controlInstructions;
+ private $bulkEditLabel;
private $description;
private $conduitDescription;
@@ -45,6 +46,7 @@
private $isConduitOnly = false;
private $conduitEditTypes;
+ private $bulkEditTypes;
public function setKey($key) {
$this->key = $key;
@@ -64,6 +66,15 @@
return $this->label;
}
+ public function setBulkEditLabel($bulk_edit_label) {
+ $this->bulkEditLabel = $bulk_edit_label;
+ return $this;
+ }
+
+ public function getBulkEditLabel() {
+ return $this->bulkEditLabel;
+ }
+
public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
return $this;
@@ -625,6 +636,22 @@
return new AphrontStringHTTPParameterType();
}
+ protected function getBulkParameterType() {
+ $type = $this->newBulkParameterType();
+
+ if (!$type) {
+ return null;
+ }
+
+ $type->setViewer($this->getViewer());
+
+ return $type;
+ }
+
+ protected function newBulkParameterType() {
+ return null;
+ }
+
public function getConduitParameterType() {
$type = $this->newConduitParameterType();
@@ -657,8 +684,15 @@
return null;
}
- return id(new PhabricatorSimpleEditType())
+ $edit_type = id(new PhabricatorSimpleEditType())
->setConduitParameterType($parameter_type);
+
+ $bulk_type = $this->getBulkParameterType();
+ if ($bulk_type) {
+ $edit_type->setBulkParameterType($bulk_type);
+ }
+
+ return $edit_type;
}
protected function getEditType() {
@@ -718,6 +752,31 @@
return array($edit_type);
}
+ final public function getBulkEditTypes() {
+ if ($this->bulkEditTypes === null) {
+ $edit_types = $this->newBulkEditTypes();
+ $edit_types = mpull($edit_types, null, 'getEditType');
+
+ foreach ($edit_types as $edit_type) {
+ $edit_type->setEditField($this);
+ }
+
+ $this->bulkEditTypes = $edit_types;
+ }
+
+ return $this->bulkEditTypes;
+ }
+
+ protected function newBulkEditTypes() {
+ $edit_type = $this->getEditType();
+
+ if (!$edit_type) {
+ return array();
+ }
+
+ return array($edit_type);
+ }
+
public function getCommentAction() {
$label = $this->getCommentActionLabel();
if ($label === null) {
diff --git a/src/applications/transactions/editfield/PhabricatorPHIDListEditField.php b/src/applications/transactions/editfield/PhabricatorPHIDListEditField.php
--- a/src/applications/transactions/editfield/PhabricatorPHIDListEditField.php
+++ b/src/applications/transactions/editfield/PhabricatorPHIDListEditField.php
@@ -104,6 +104,10 @@
return $type;
}
+ protected function newBulkEditTypes() {
+ return $this->newConduitEditTypes();
+ }
+
protected function newConduitEditTypes() {
if (!$this->getUseEdgeTransactions()) {
return parent::newConduitEditTypes();
diff --git a/src/applications/transactions/editfield/PhabricatorTextEditField.php b/src/applications/transactions/editfield/PhabricatorTextEditField.php
--- a/src/applications/transactions/editfield/PhabricatorTextEditField.php
+++ b/src/applications/transactions/editfield/PhabricatorTextEditField.php
@@ -29,4 +29,8 @@
return new ConduitStringParameterType();
}
+ protected function newBulkParameterType() {
+ return new BulkStringParameterType();
+ }
+
}
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
@@ -14,6 +14,9 @@
private $conduitTypeDescription;
private $conduitParameterType;
+ private $bulkParameterType;
+ private $bulkEditLabel;
+
public function setLabel($label) {
$this->label = $label;
return $this;
@@ -23,6 +26,19 @@
return $this->label;
}
+ public function setBulkEditLabel($bulk_edit_label) {
+ $this->bulkEditLabel = $bulk_edit_label;
+ return $this;
+ }
+
+ public function getBulkEditLabel() {
+ if ($this->bulkEditLabel !== null) {
+ return $this->bulkEditLabel;
+ }
+
+ return $this->getField()->getBulkEditLabel();
+ }
+
public function setField(PhabricatorEditField $field) {
$this->field = $field;
return $this;
@@ -85,6 +101,30 @@
return $this->editField;
}
+
+/* -( Bulk )--------------------------------------------------------------- */
+
+
+ protected function newBulkParameterType() {
+ if ($this->bulkParameterType) {
+ return clone $this->bulkParameterType;
+ }
+
+ return null;
+ }
+
+
+ public function setBulkParameterType(BulkParameterType $type) {
+ $this->bulkParameterType = $type;
+ return $this;
+ }
+
+
+ public function getBulkParameterType() {
+ return $this->newBulkParameterType();
+ }
+
+
/* -( Conduit )------------------------------------------------------------ */
diff --git a/webroot/rsrc/css/application/maniphest/batch-editor.css b/webroot/rsrc/css/application/maniphest/batch-editor.css
deleted file mode 100644
--- a/webroot/rsrc/css/application/maniphest/batch-editor.css
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * @provides maniphest-batch-editor
- */
-.maniphest-batch-actions-table {
- width: 100%;
- margin: 12px 0;
-}
-
-.maniphest-batch-actions-table td {
- padding: 4px 8px;
- vertical-align: middle;
-}
-
-.batch-editor-input {
- width: 100%;
- text-align: left;
-}
diff --git a/webroot/rsrc/css/phui/phui-bulk-editor.css b/webroot/rsrc/css/phui/phui-bulk-editor.css
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/css/phui/phui-bulk-editor.css
@@ -0,0 +1,22 @@
+/**
+ * @provides phui-bulk-editor-css
+ */
+
+.bulk-edit-table {
+ width: 100%;
+ margin: 12px 0;
+}
+
+.bulk-edit-table td {
+ padding: 4px 8px;
+ vertical-align: middle;
+}
+
+.bulk-edit-input {
+ width: 100%;
+ text-align: left;
+}
+
+.bulk-edit-input input {
+ width: 100%;
+}
diff --git a/webroot/rsrc/js/application/maniphest/behavior-batch-editor.js b/webroot/rsrc/js/application/maniphest/behavior-batch-editor.js
deleted file mode 100644
--- a/webroot/rsrc/js/application/maniphest/behavior-batch-editor.js
+++ /dev/null
@@ -1,158 +0,0 @@
-/**
- * @provides javelin-behavior-maniphest-batch-editor
- * @requires javelin-behavior
- * javelin-dom
- * javelin-util
- * phabricator-prefab
- * multirow-row-manager
- * javelin-json
- */
-
-JX.behavior('maniphest-batch-editor', function(config) {
- var root = JX.$(config.root);
- var editor_table = JX.DOM.find(root, 'table', 'maniphest-batch-actions');
- var manager = new JX.MultirowRowManager(editor_table);
- var action_rows = [];
-
- function renderRow() {
- var action_select = JX.Prefab.renderSelect(
- {
- 'add_project': 'Add Projects',
- 'remove_project' : 'Remove Projects',
- 'priority': 'Change Priority',
- 'status': 'Change Status',
- 'add_comment': 'Comment',
- 'assign': 'Assign',
- 'add_ccs' : 'Add CCs',
- 'remove_ccs' : 'Remove CCs',
- 'space': 'Shift to Space'
- });
-
- var proj_tokenizer = build_tokenizer(config.sources.project);
- var owner_tokenizer = build_tokenizer(config.sources.owner);
- var cc_tokenizer = build_tokenizer(config.sources.cc);
- var space_tokenizer = build_tokenizer(config.sources.spaces);
-
- var priority_select = JX.Prefab.renderSelect(config.priorityMap);
- var status_select = JX.Prefab.renderSelect(config.statusMap);
- var comment_input = JX.$N('input', {style: {width: '100%'}});
-
- var cell = JX.$N('td', {className: 'batch-editor-input'});
- var vfunc = null;
-
- function update() {
- switch (action_select.value) {
- case 'add_project':
- case 'remove_project':
- JX.DOM.setContent(cell, proj_tokenizer.template);
- vfunc = function() {
- return JX.keys(proj_tokenizer.object.getTokens());
- };
- break;
- case 'add_ccs':
- case 'remove_ccs':
- JX.DOM.setContent(cell, cc_tokenizer.template);
- vfunc = function() {
- return JX.keys(cc_tokenizer.object.getTokens());
- };
- break;
- case 'assign':
- JX.DOM.setContent(cell, owner_tokenizer.template);
- vfunc = function() {
- return JX.keys(owner_tokenizer.object.getTokens());
- };
- break;
- case 'space':
- JX.DOM.setContent(cell, space_tokenizer.template);
- vfunc = function() {
- return JX.keys(space_tokenizer.object.getTokens());
- };
- break;
- case 'add_comment':
- JX.DOM.setContent(cell, comment_input);
- vfunc = function() {
- return comment_input.value;
- };
- break;
- case 'priority':
- JX.DOM.setContent(cell, priority_select);
- vfunc = function() { return priority_select.value; };
- break;
- case 'status':
- JX.DOM.setContent(cell, status_select);
- vfunc = function() { return status_select.value; };
- break;
- }
- }
-
- JX.DOM.listen(action_select, 'change', null, update);
- update();
-
- return {
- nodes : [JX.$N('td', {}, action_select), cell],
- dataCallback : function() {
- return {
- action: action_select.value,
- value: vfunc()
- };
- }
- };
- }
-
- function onaddaction(e) {
- e.kill();
- addRow({});
- }
-
- function addRow(info) {
- var data = renderRow(info);
- var row = manager.addRow(data.nodes);
- var id = manager.getRowID(row);
-
- action_rows[id] = data.dataCallback;
- }
-
- function onsubmit() {
- var input = JX.$(config.input);
-
- var actions = [];
- for (var k in action_rows) {
- actions.push(action_rows[k]());
- }
-
- input.value = JX.JSON.stringify(actions);
- }
-
- addRow({});
-
- JX.DOM.listen(
- root,
- 'click',
- 'add-action',
- onaddaction);
-
- JX.DOM.listen(
- root,
- 'submit',
- null,
- onsubmit);
-
- manager.listen(
- 'row-removed',
- function(row_id) {
- delete action_rows[row_id];
- });
-
- function build_tokenizer(tconfig) {
- var built = JX.Prefab.newTokenizerFromTemplate(
- config.tokenizerTemplate,
- JX.copy({}, tconfig));
- built.tokenizer.start();
-
- return {
- object: built.tokenizer,
- template: built.node
- };
- }
-
-});
diff --git a/webroot/rsrc/js/core/behavior-bulk-editor.js b/webroot/rsrc/js/core/behavior-bulk-editor.js
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/js/core/behavior-bulk-editor.js
@@ -0,0 +1,113 @@
+/**
+ * @provides javelin-behavior-bulk-editor
+ * @requires javelin-behavior
+ * javelin-dom
+ * javelin-util
+ * phabricator-prefab
+ * multirow-row-manager
+ * javelin-json
+ * phuix-form-control-view
+ */
+
+JX.behavior('bulk-editor', function(config) {
+
+ var root = JX.$(config.rootNodeID);
+ var editor_table = JX.DOM.find(root, 'table', 'bulk-actions');
+
+ var manager = new JX.MultirowRowManager(editor_table);
+ var action_rows = [];
+
+ var option_map = {};
+ var option_order = [];
+ var spec_map = {};
+
+ for (var ii = 0; ii < config.edits.length; ii++) {
+ var edit = config.edits[ii];
+
+ option_map[edit.xaction] = edit.label;
+ option_order.push(edit.xaction);
+
+ spec_map[edit.xaction] = edit;
+ }
+
+ function renderRow() {
+ var action_select = JX.Prefab.renderSelect(
+ option_map,
+ null,
+ null,
+ option_order);
+
+ var cell = JX.$N('td', {className: 'bulk-edit-input'});
+ var vfunc = null;
+
+ function update() {
+ var spec = spec_map[action_select.value];
+ var control = spec.control;
+
+ var phuix = new JX.PHUIXFormControl()
+ .setControl(control.type, control.spec);
+
+ JX.DOM.setContent(cell, phuix.getRawInputNode());
+
+ vfunc = JX.bind(phuix, phuix.getValue);
+ }
+
+ JX.DOM.listen(action_select, 'change', null, update);
+ update();
+
+ return {
+ nodes : [JX.$N('td', {}, action_select), cell],
+ dataCallback : function() {
+ return {
+ type: action_select.value,
+ value: vfunc()
+ };
+ }
+ };
+ }
+
+ function onaddaction(e) {
+ e.kill();
+ addRow({});
+ }
+
+ function addRow(info) {
+ var data = renderRow(info);
+ var row = manager.addRow(data.nodes);
+ var id = manager.getRowID(row);
+
+ action_rows[id] = data.dataCallback;
+ }
+
+ function onsubmit() {
+ var input = JX.$(config.inputNodeID);
+
+ var actions = [];
+ for (var k in action_rows) {
+ actions.push(action_rows[k]());
+ }
+
+ input.value = JX.JSON.stringify(actions);
+ }
+
+ addRow({});
+
+ JX.DOM.listen(
+ root,
+ 'click',
+ 'add-action',
+ onaddaction);
+
+ JX.DOM.listen(
+ root,
+ 'submit',
+ null,
+ onsubmit);
+
+ manager.listen(
+ 'row-removed',
+ function(row_id) {
+ delete action_rows[row_id];
+ });
+
+});
diff --git a/webroot/rsrc/js/phuix/PHUIXFormControl.js b/webroot/rsrc/js/phuix/PHUIXFormControl.js
--- a/webroot/rsrc/js/phuix/PHUIXFormControl.js
+++ b/webroot/rsrc/js/phuix/PHUIXFormControl.js
@@ -14,6 +14,7 @@
_className: null,
_valueSetCallback: null,
_valueGetCallback: null,
+ _rawInputNode: null,
setLabel: function(label) {
JX.DOM.setContent(this._getLabelNode(), label);
@@ -53,6 +54,9 @@
case 'checkboxes':
input = this._newCheckboxes(spec);
break;
+ case 'text':
+ input = this._newText(spec);
+ break;
default:
// TODO: Default or better error?
JX.$E('Bad Input Type');
@@ -62,6 +66,7 @@
JX.DOM.setContent(node, input.node);
this._valueGetCallback = input.get;
this._valueSetCallback = input.set;
+ this._rawInputNode = input.node;
return this;
},
@@ -75,6 +80,10 @@
return this._valueGetCallback();
},
+ getRawInputNode: function() {
+ return this._rawInputNode;
+ },
+
getNode: function() {
if (!this._node) {
@@ -281,6 +290,10 @@
},
_newPoints: function(spec) {
+ return this._newText();
+ },
+
+ _newText: function(spec) {
var attrs = {
type: 'text',
value: spec.value

File Metadata

Mime Type
text/plain
Expires
Sat, Oct 19, 12:10 AM (4 w, 1 d ago)
Storage Engine
amazon-s3
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
phabricator/secure/jv/k3/dubnybbmdag34cdl
Default Alt Text
D18863.diff (32 KB)

Event Timeline