@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3final class PhabricatorProjectBoardReorderController
4 extends PhabricatorProjectBoardController {
5
6 public function handleRequest(AphrontRequest $request) {
7 $viewer = $request->getViewer();
8 $projectid = $request->getURIData('projectID');
9
10 $project = id(new PhabricatorProjectQuery())
11 ->setViewer($viewer)
12 ->requireCapabilities(
13 array(
14 PhabricatorPolicyCapability::CAN_VIEW,
15 PhabricatorPolicyCapability::CAN_EDIT,
16 ))
17 ->withIDs(array($projectid))
18 ->executeOne();
19 if (!$project) {
20 return new Aphront404Response();
21 }
22
23 $this->setProject($project);
24 $project_id = $project->getID();
25
26 $view_uri = $this->getApplicationURI("board/{$project_id}/");
27 $reorder_uri = $this->getApplicationURI("board/{$project_id}/reorder/");
28
29 if ($request->isFormPost()) {
30 // User clicked "Done", make sure the page reloads to show the new
31 // column order.
32 return id(new AphrontRedirectResponse())->setURI($view_uri);
33 }
34
35 $columns = id(new PhabricatorProjectColumnQuery())
36 ->setViewer($viewer)
37 ->withProjectPHIDs(array($project->getPHID()))
38 ->execute();
39 $columns = msort($columns, 'getSequence');
40
41 $column_phid = $request->getStr('columnPHID');
42 if ($column_phid && $request->validateCSRF()) {
43
44 $columns = mpull($columns, null, 'getPHID');
45 if (empty($columns[$column_phid])) {
46 return new Aphront404Response();
47 }
48
49 $target_column = $columns[$column_phid];
50 $new_sequence = $request->getInt('sequence');
51 if ($new_sequence < 0) {
52 return new Aphront404Response();
53 }
54
55 // TODO: For now, we're not recording any transactions here. We probably
56 // should, but this sort of edit is extremely trivial.
57
58 // Resequence the columns so that the moved column has the correct
59 // sequence number. Move columns after it up one place in the sequence.
60 $new_map = array();
61 foreach ($columns as $phid => $column) {
62 $value = $column->getSequence();
63 if ($column->getPHID() == $column_phid) {
64 $value = $new_sequence;
65 } else if ($column->getSequence() >= $new_sequence) {
66 $value = $value + 1;
67 }
68 $new_map[$phid] = $value;
69 }
70
71 // Sort the columns into their new ordering.
72 asort($new_map);
73
74 // Now, compact the ordering and adjust any columns that need changes.
75 $project->openTransaction();
76 $sequence = 0;
77 foreach ($new_map as $phid => $ignored) {
78 $new_value = $sequence++;
79 $cur_value = $columns[$phid]->getSequence();
80 if ($new_value != $cur_value) {
81 $columns[$phid]->setSequence($new_value)->save();
82 }
83 }
84 $project->saveTransaction();
85
86 return id(new AphrontAjaxResponse())->setContent(
87 array(
88 'sequenceMap' => mpull($columns, 'getSequence', 'getPHID'),
89 ));
90 }
91
92 $list_id = celerity_generate_unique_node_id();
93
94 $list = id(new PHUIObjectItemListView())
95 ->setUser($viewer)
96 ->setID($list_id)
97 ->setFlush(true)
98 ->setDrag(true);
99
100 foreach ($columns as $column) {
101 // Don't allow milestone columns to be reordered.
102 $proxy = $column->getProxy();
103 if ($proxy && $proxy->isMilestone()) {
104 continue;
105 }
106
107 // At least for now, don't show subproject column.
108 if ($proxy) {
109 continue;
110 }
111
112 $item = id(new PHUIObjectItemView())
113 ->setHeader($column->getDisplayName())
114 ->addIcon($column->getHeaderIcon(), $column->getDisplayType());
115
116 if ($column->isHidden()) {
117 $item->setDisabled(true);
118 }
119
120 $item->setGrippable(true);
121 $item->addSigil('board-column');
122 $item->setMetadata(
123 array(
124 'columnPHID' => $column->getPHID(),
125 'columnSequence' => $column->getSequence(),
126 ));
127
128 $list->addItem($item);
129 }
130
131 Javelin::initBehavior(
132 'reorder-columns',
133 array(
134 'listID' => $list_id,
135 'reorderURI' => $reorder_uri,
136 ));
137
138 return $this->newDialog()
139 ->setTitle(pht('Reorder Columns'))
140 ->setWidth(AphrontDialogView::WIDTH_FORM)
141 ->appendChild($list)
142 ->addSubmitButton(pht('Done'));
143 }
144
145}