Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14005486
D18863.id45246.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
27 KB
Referenced Files
None
Subscribers
None
D18863.id45246.diff
View Options
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',
@@ -477,6 +477,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 +533,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 +596,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',
@@ -756,7 +758,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 +824,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 +886,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 +1389,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 +1447,10 @@
'javelin-dom',
'phuix-button-view',
),
+ '68bb05aa' => array(
+ 'javelin-install',
+ 'javelin-dom',
+ ),
'69adf288' => array(
'javelin-install',
),
@@ -1570,10 +1585,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/PhabricatorEditEngineBulkJobType.php b/src/applications/transactions/bulk/PhabricatorEditEngineBulkJobType.php
--- a/src/applications/transactions/bulk/PhabricatorEditEngineBulkJobType.php
+++ b/src/applications/transactions/bulk/PhabricatorEditEngineBulkJobType.php
@@ -71,11 +71,7 @@
foreach ($raw_xactions as $raw_xaction) {
$xaction = $object->getApplicationTransactionTemplate()
->setTransactionType($raw_xaction['type'])
- ->setNewValue($raw_xaction['new']);
-
- if (array_key_exists('old', $raw_xaction)) {
- $xaction->setOldValue($raw_xaction['old']);
- }
+ ->setNewValue($raw_xaction['value']);
$xactions[] = $xaction;
}
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/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
Details
Attached
Mime Type
text/plain
Expires
Mon, Oct 28, 1:57 PM (2 w, 5 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6753031
Default Alt Text
D18863.id45246.diff (27 KB)
Attached To
Mode
D18863: Define bulk edits in terms of EditEngine, not hard-coded ad-hoc definitions
Attached
Detach File
Event Timeline
Log In to Comment