Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15419795
D9905.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
12 KB
Referenced Files
None
Subscribers
None
D9905.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
@@ -413,6 +413,7 @@
'rsrc/js/application/projects/behavior-boards-dropdown.js' => '0ec56e1d',
'rsrc/js/application/projects/behavior-project-boards.js' => 'c6b95cbd',
'rsrc/js/application/projects/behavior-project-create.js' => '065227cc',
+ 'rsrc/js/application/projects/behavior-reorder-columns.js' => '09eee344',
'rsrc/js/application/releeph/releeph-preview-branch.js' => 'b2b4fbaf',
'rsrc/js/application/releeph/releeph-request-state-change.js' => 'ab836011',
'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'de2e896f',
@@ -645,6 +646,7 @@
'javelin-behavior-releeph-request-typeahead' => 'de2e896f',
'javelin-behavior-remarkup-preview' => 'f7379f45',
'javelin-behavior-reorder-applications' => '76b9fc3e',
+ 'javelin-behavior-reorder-columns' => '09eee344',
'javelin-behavior-repository-crossreference' => 'f9539603',
'javelin-behavior-search-reorder-queries' => 'e9581f08',
'javelin-behavior-select-on-click' => '4e3e79a6',
@@ -872,6 +874,14 @@
4 => 'javelin-util',
5 => 'phabricator-busy',
),
+ '09eee344' =>
+ array(
+ 0 => 'javelin-behavior',
+ 1 => 'javelin-stratcom',
+ 2 => 'javelin-workflow',
+ 3 => 'javelin-dom',
+ 4 => 'phabricator-draggable-list',
+ ),
'0a3f3021' =>
array(
0 => 'javelin-behavior',
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
@@ -1971,6 +1971,7 @@
'PhabricatorProjectBoardController' => 'applications/project/controller/PhabricatorProjectBoardController.php',
'PhabricatorProjectBoardDeleteController' => 'applications/project/controller/PhabricatorProjectBoardDeleteController.php',
'PhabricatorProjectBoardEditController' => 'applications/project/controller/PhabricatorProjectBoardEditController.php',
+ 'PhabricatorProjectBoardReorderController' => 'applications/project/controller/PhabricatorProjectBoardReorderController.php',
'PhabricatorProjectBoardViewController' => 'applications/project/controller/PhabricatorProjectBoardViewController.php',
'PhabricatorProjectColumn' => 'applications/project/storage/PhabricatorProjectColumn.php',
'PhabricatorProjectColumnDetailController' => 'applications/project/controller/PhabricatorProjectColumnDetailController.php',
@@ -4842,6 +4843,7 @@
'PhabricatorProjectBoardController' => 'PhabricatorProjectController',
'PhabricatorProjectBoardDeleteController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectBoardEditController' => 'PhabricatorProjectBoardController',
+ 'PhabricatorProjectBoardReorderController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectBoardViewController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectColumn' =>
array(
diff --git a/src/applications/project/application/PhabricatorApplicationProject.php b/src/applications/project/application/PhabricatorApplicationProject.php
--- a/src/applications/project/application/PhabricatorApplicationProject.php
+++ b/src/applications/project/application/PhabricatorApplicationProject.php
@@ -64,12 +64,16 @@
'(?:query/(?P<queryKey>[^/]+)/)?' =>
'PhabricatorProjectBoardViewController',
'move/(?P<id>[1-9]\d*)/' => 'PhabricatorProjectMoveController',
- 'board/(?P<projectID>[1-9]\d*)/edit/(?:(?P<id>\d+)/)?'
- => 'PhabricatorProjectBoardEditController',
- 'board/(?P<projectID>[1-9]\d*)/delete/(?:(?P<id>\d+)/)?'
- => 'PhabricatorProjectBoardDeleteController',
- 'board/(?P<projectID>[1-9]\d*)/column/(?:(?P<id>\d+)/)?'
- => 'PhabricatorProjectColumnDetailController',
+ 'board/(?P<projectID>[1-9]\d*)/' => array(
+ 'edit/(?:(?P<id>\d+)/)?'
+ => 'PhabricatorProjectBoardEditController',
+ 'delete/(?:(?P<id>\d+)/)?'
+ => 'PhabricatorProjectBoardDeleteController',
+ 'column/(?:(?P<id>\d+)/)?'
+ => 'PhabricatorProjectColumnDetailController',
+ 'reorder/'
+ => 'PhabricatorProjectBoardReorderController',
+ ),
'update/(?P<id>[1-9]\d*)/(?P<action>[^/]+)/'
=> 'PhabricatorProjectUpdateController',
'history/(?P<id>[1-9]\d*)/' => 'PhabricatorProjectHistoryController',
diff --git a/src/applications/project/controller/PhabricatorProjectBoardReorderController.php b/src/applications/project/controller/PhabricatorProjectBoardReorderController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/controller/PhabricatorProjectBoardReorderController.php
@@ -0,0 +1,157 @@
+<?php
+
+final class PhabricatorProjectBoardReorderController
+ extends PhabricatorProjectBoardController {
+
+ private $projectID;
+
+ public function willProcessRequest(array $data) {
+ $this->projectID = $data['projectID'];
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+
+ $project = id(new PhabricatorProjectQuery())
+ ->setViewer($viewer)
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->withIDs(array($this->projectID))
+ ->executeOne();
+ if (!$project) {
+ return new Aphront404Response();
+ }
+
+ $this->setProject($project);
+
+
+ $project_id = $project->getID();
+
+ $board_uri = $this->getApplicationURI("board/{$project_id}/");
+ $reorder_uri = $this->getApplicationURI("board/{$project_id}/reorder/");
+
+ if ($request->isFormPost()) {
+ // User clicked "Done", make sure the page reloads to show the new
+ // column order.
+ return id(new AphrontRedirectResponse())->setURI($board_uri);
+ }
+
+ $columns = id(new PhabricatorProjectColumnQuery())
+ ->setViewer($viewer)
+ ->withProjectPHIDs(array($project->getPHID()))
+ ->execute();
+ $columns = msort($columns, 'getSequence');
+
+ $column_phid = $request->getStr('columnPHID');
+ if ($column_phid && $request->validateCSRF()) {
+
+ $columns = mpull($columns, null, 'getPHID');
+ if (empty($columns[$column_phid])) {
+ return new Aphront404Response();
+ }
+
+ // TODO: We could let you move the backlog column around if you really
+ // want, but for now we use sequence position 0 as magic.
+ $target_column = $columns[$column_phid];
+ $new_sequence = $request->getInt('sequence');
+ if ($target_column->isDefaultColumn() || $new_sequence < 1) {
+ return new Aphront404Response();
+ }
+
+ // TODO: For now, we're not recording any transactions here. We probably
+ // should, but this sort of edit is extremely trivial.
+
+ // Resequence the columns so that the moved column has the correct
+ // sequence number. Move columns after it up one place in the sequence.
+ $new_map = array();
+ foreach ($columns as $phid => $column) {
+ $value = $column->getSequence();
+ if ($column->getPHID() == $column_phid) {
+ $value = $new_sequence;
+ } else if ($column->getSequence() >= $new_sequence) {
+ $value = $value + 1;
+ }
+ $new_map[$phid] = $value;
+ }
+
+ // Sort the columns into their new ordering.
+ asort($new_map);
+
+ // Now, compact the ordering and adjust any columns that need changes.
+ $project->openTransaction();
+ $sequence = 0;
+ foreach ($new_map as $phid => $ignored) {
+ $new_value = $sequence++;
+ $cur_value = $columns[$phid]->getSequence();
+ if ($new_value != $cur_value) {
+ $columns[$phid]->setSequence($new_value)->save();
+ }
+ }
+ $project->saveTransaction();
+
+ return id(new AphrontAjaxResponse())->setContent(
+ array(
+ 'sequenceMap' => mpull($columns, 'getSequence', 'getPHID'),
+ ));
+ }
+
+ $list_id = celerity_generate_unique_node_id();
+
+ $static_list = id(new PHUIObjectItemListView())
+ ->setUser($viewer)
+ ->setFlush(true)
+ ->setStackable(true);
+
+ $list = id(new PHUIObjectItemListView())
+ ->setUser($viewer)
+ ->setID($list_id)
+ ->setFlush(true)
+ ->setStackable(true);
+
+ foreach ($columns as $column) {
+ $item = id(new PHUIObjectItemView())
+ ->setHeader($column->getDisplayName());
+
+ if ($column->isHidden()) {
+ $item->setDisabled(true);
+ }
+
+ if ($column->isDefaultColumn()) {
+ $item->setDisabled(true);
+ $static_list->addItem($item);
+ } else {
+ $item->setGrippable(true);
+ $item->addSigil('board-column');
+ $item->setMetadata(
+ array(
+ 'columnPHID' => $column->getPHID(),
+ 'columnSequence' => $column->getSequence(),
+ ));
+
+ $list->addItem($item);
+ }
+
+ }
+
+ Javelin::initBehavior(
+ 'reorder-columns',
+ array(
+ 'listID' => $list_id,
+ 'reorderURI' => $reorder_uri,
+ ));
+
+ return $this->newDialog()
+ ->setTitle(pht('Reorder Columns'))
+ ->setWidth(AphrontDialogView::WIDTH_FORM)
+ ->appendParagraph(pht('This column can not be moved:'))
+ ->appendChild($static_list)
+ ->appendParagraph(pht('Drag and drop these columns to reorder them:'))
+ ->appendChild($list)
+ ->addSubmitButton(pht('Done'));
+ }
+
+}
diff --git a/src/applications/project/controller/PhabricatorProjectBoardViewController.php b/src/applications/project/controller/PhabricatorProjectBoardViewController.php
--- a/src/applications/project/controller/PhabricatorProjectBoardViewController.php
+++ b/src/applications/project/controller/PhabricatorProjectBoardViewController.php
@@ -357,7 +357,16 @@
$manage_items[] = id(new PhabricatorActionView())
->setIcon('fa-plus')
->setName(pht('Add Column'))
- ->setHref($this->getApplicationURI('board/'.$this->id.'/edit/'));
+ ->setHref($this->getApplicationURI('board/'.$this->id.'/edit/'))
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(!$can_edit);
+
+ $manage_items[] = id(new PhabricatorActionView())
+ ->setIcon('fa-exchange')
+ ->setName(pht('Reorder Columns'))
+ ->setHref($this->getApplicationURI('board/'.$this->id.'/reorder/'))
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(true);
if ($show_hidden) {
$hidden_uri = $request->getRequestURI()
diff --git a/webroot/rsrc/js/application/projects/behavior-reorder-columns.js b/webroot/rsrc/js/application/projects/behavior-reorder-columns.js
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/js/application/projects/behavior-reorder-columns.js
@@ -0,0 +1,58 @@
+/**
+ * @provides javelin-behavior-reorder-columns
+ * @requires javelin-behavior
+ * javelin-stratcom
+ * javelin-workflow
+ * javelin-dom
+ * phabricator-draggable-list
+ */
+
+JX.behavior('reorder-columns', function(config) {
+
+ var root = JX.$(config.listID);
+
+ var list = new JX.DraggableList('board-column', root)
+ .setFindItemsHandler(function() {
+ return JX.DOM.scry(root, 'li', 'board-column');
+ });
+
+ list.listen('didDrop', function(node) {
+ var nodes = list.findItems();
+
+ var node_data = JX.Stratcom.getData(node);
+
+ // Find the column sequence of the previous node.
+ var sequence = null;
+ var data;
+ for (var ii = 0; ii < nodes.length; ii++) {
+ data = JX.Stratcom.getData(nodes[ii]);
+ if (data.columnPHID === node_data.columnPHID) {
+ break;
+ }
+ sequence = data.columnSequence;
+ }
+
+ list.lock();
+ JX.DOM.alterClass(node, 'drag-sending', true);
+
+ var parameters = {
+ columnPHID: node_data.columnPHID,
+ sequence: (sequence === null) ? 1 : (parseInt(sequence, 10) + 1)
+ };
+
+ new JX.Workflow(config.reorderURI, parameters)
+ .setHandler(function(r) {
+
+ // Adjust metadata for the new sequence numbers.
+ for (var ii = 0; ii < nodes.length; ii++) {
+ var data = JX.Stratcom.getData(nodes[ii]);
+ data.columnSequence = r.sequenceMap[data.columnPHID];
+ }
+
+ list.unlock();
+ JX.DOM.alterClass(node, 'drag-sending', false);
+ })
+ .start();
+ });
+
+});
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Mar 22, 8:58 AM (1 d, 17 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7225408
Default Alt Text
D9905.diff (12 KB)
Attached To
Mode
D9905: Allow board columns to be reordered
Attached
Detach File
Event Timeline
Log In to Comment