@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
fork

Configure Feed

Select the types of activity you want to include in your feed.

Make "Move Panel" on dashboards use the new storage and transactions

Summary: Depends on D20408. Ref T13272. The actual JS is still a little bit iffy, but this makes the server side "move" operation work correctly by updating it to use the same code as everything else.

Test Plan: Moved panels around on single-column and multi-column dashboards, saw them move to reasonable places and stay there when I reloaded the page.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13272

Differential Revision: https://secure.phabricator.com/D20409

+120 -132
+13 -13
resources/celerity/map.php
··· 9 9 'names' => array( 10 10 'conpherence.pkg.css' => '3c8a0668', 11 11 'conpherence.pkg.js' => '020aebcf', 12 - 'core.pkg.css' => '294e365c', 12 + 'core.pkg.css' => '4011a01e', 13 13 'core.pkg.js' => '69247edd', 14 14 'differential.pkg.css' => '8d8360fb', 15 15 'differential.pkg.js' => '67e02996', ··· 132 132 'rsrc/css/phui/object-item/phui-oi-color.css' => 'b517bfa0', 133 133 'rsrc/css/phui/object-item/phui-oi-drag-ui.css' => 'da15d3dc', 134 134 'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '490e2e2e', 135 - 'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'f14f2422', 135 + 'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'd7723ecc', 136 136 'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => '6a30fa46', 137 137 'rsrc/css/phui/phui-action-list.css' => '48a45c51', 138 138 'rsrc/css/phui/phui-action-panel.css' => '6c386cbf', ··· 372 372 'rsrc/js/application/countdown/timer.js' => '6a162524', 373 373 'rsrc/js/application/daemon/behavior-bulk-job-reload.js' => '3829a3cf', 374 374 'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => 'a871fe00', 375 - 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '076bd092', 375 + 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '7d33143d', 376 376 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '1e413dc9', 377 377 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => '0116d3e8', 378 378 'rsrc/js/application/diff/DiffChangeset.js' => 'd0a85a85', ··· 595 595 'javelin-behavior-countdown-timer' => '6a162524', 596 596 'javelin-behavior-dark-console' => 'f39d968b', 597 597 'javelin-behavior-dashboard-async-panel' => 'a871fe00', 598 - 'javelin-behavior-dashboard-move-panels' => '076bd092', 598 + 'javelin-behavior-dashboard-move-panels' => '7d33143d', 599 599 'javelin-behavior-dashboard-query-panel-select' => '1e413dc9', 600 600 'javelin-behavior-dashboard-tab-panel' => '0116d3e8', 601 601 'javelin-behavior-day-view' => '727a5a61', ··· 853 853 'phui-oi-color-css' => 'b517bfa0', 854 854 'phui-oi-drag-ui-css' => 'da15d3dc', 855 855 'phui-oi-flush-ui-css' => '490e2e2e', 856 - 'phui-oi-list-view-css' => 'f14f2422', 856 + 'phui-oi-list-view-css' => 'd7723ecc', 857 857 'phui-oi-simple-ui-css' => '6a30fa46', 858 858 'phui-pager-css' => 'd022c7ad', 859 859 'phui-pinboard-view-css' => '1f08f5d8', ··· 964 964 'javelin-request', 965 965 'javelin-uri', 966 966 ), 967 - '076bd092' => array( 968 - 'javelin-behavior', 969 - 'javelin-dom', 970 - 'javelin-util', 971 - 'javelin-stratcom', 972 - 'javelin-workflow', 973 - 'phabricator-draggable-list', 974 - ), 975 967 '0889b835' => array( 976 968 'javelin-install', 977 969 'javelin-event', ··· 1588 1580 '7c4d8998' => array( 1589 1581 'javelin-install', 1590 1582 'javelin-dom', 1583 + ), 1584 + '7d33143d' => array( 1585 + 'javelin-behavior', 1586 + 'javelin-dom', 1587 + 'javelin-util', 1588 + 'javelin-stratcom', 1589 + 'javelin-workflow', 1590 + 'phabricator-draggable-list', 1591 1591 ), 1592 1592 '80bff3af' => array( 1593 1593 'javelin-install',
-2
src/__phutil_library_map__.php
··· 2930 2930 'PhabricatorDashboardLayoutMode' => 'applications/dashboard/layoutconfig/PhabricatorDashboardLayoutMode.php', 2931 2931 'PhabricatorDashboardLayoutTransaction' => 'applications/dashboard/xaction/dashboard/PhabricatorDashboardLayoutTransaction.php', 2932 2932 'PhabricatorDashboardListController' => 'applications/dashboard/controller/PhabricatorDashboardListController.php', 2933 - 'PhabricatorDashboardMovePanelController' => 'applications/dashboard/controller/PhabricatorDashboardMovePanelController.php', 2934 2933 'PhabricatorDashboardNameTransaction' => 'applications/dashboard/xaction/dashboard/PhabricatorDashboardNameTransaction.php', 2935 2934 'PhabricatorDashboardNgrams' => 'applications/dashboard/storage/PhabricatorDashboardNgrams.php', 2936 2935 'PhabricatorDashboardObjectInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardObjectInstallWorkflow.php', ··· 8929 8928 'PhabricatorDashboardLayoutMode' => 'Phobject', 8930 8929 'PhabricatorDashboardLayoutTransaction' => 'PhabricatorDashboardTransactionType', 8931 8930 'PhabricatorDashboardListController' => 'PhabricatorDashboardController', 8932 - 'PhabricatorDashboardMovePanelController' => 'PhabricatorDashboardController', 8933 8931 'PhabricatorDashboardNameTransaction' => 'PhabricatorDashboardTransactionType', 8934 8932 'PhabricatorDashboardNgrams' => 'PhabricatorSearchNgrams', 8935 8933 'PhabricatorDashboardObjectInstallWorkflow' => 'PhabricatorDashboardInstallWorkflow',
+1 -2
src/applications/dashboard/application/PhabricatorDashboardApplication.php
··· 48 48 '(?:(?P<modeKey>[^/]+)/)?)?' => 49 49 'PhabricatorDashboardInstallController', 50 50 'console/' => 'PhabricatorDashboardConsoleController', 51 - 'movepanel/(?P<id>\d+)/' => 'PhabricatorDashboardMovePanelController', 52 - 'adjust/(?P<op>remove|add)/' 51 + 'adjust/(?P<op>remove|add|move)/' 53 52 => 'PhabricatorDashboardAdjustController', 54 53 'panel/' => array( 55 54 'install/(?P<engineKey>[^/]+)/(?:(?P<queryKey>[^/]+)/)?' =>
-70
src/applications/dashboard/controller/PhabricatorDashboardMovePanelController.php
··· 1 - <?php 2 - 3 - final class PhabricatorDashboardMovePanelController 4 - extends PhabricatorDashboardController { 5 - 6 - public function handleRequest(AphrontRequest $request) { 7 - $viewer = $request->getViewer(); 8 - $id = $request->getURIData('id'); 9 - 10 - $column_id = $request->getStr('columnID'); 11 - $panel_phid = $request->getStr('objectPHID'); 12 - $after_phid = $request->getStr('afterPHID'); 13 - $before_phid = $request->getStr('beforePHID'); 14 - 15 - $dashboard = id(new PhabricatorDashboardQuery()) 16 - ->setViewer($viewer) 17 - ->withIDs(array($id)) 18 - ->requireCapabilities( 19 - array( 20 - PhabricatorPolicyCapability::CAN_VIEW, 21 - PhabricatorPolicyCapability::CAN_EDIT, 22 - )) 23 - ->executeOne(); 24 - if (!$dashboard) { 25 - return new Aphront404Response(); 26 - } 27 - $panels = mpull($dashboard->getPanels(), null, 'getPHID'); 28 - $panel = idx($panels, $panel_phid); 29 - if (!$panel) { 30 - return new Aphront404Response(); 31 - } 32 - 33 - $layout_config = $dashboard->getLayoutConfigObject(); 34 - $layout_config->removePanel($panel_phid); 35 - $panel_location_grid = $layout_config->getPanelLocations(); 36 - 37 - $column_phids = idx($panel_location_grid, $column_id, array()); 38 - $column_phids = array_values($column_phids); 39 - if ($column_phids) { 40 - $insert_at = 0; 41 - foreach ($column_phids as $index => $phid) { 42 - if ($phid === $before_phid) { 43 - $insert_at = $index; 44 - break; 45 - } 46 - if ($phid === $after_phid) { 47 - $insert_at = $index + 1; 48 - break; 49 - } 50 - } 51 - 52 - $new_column_phids = $column_phids; 53 - array_splice( 54 - $new_column_phids, 55 - $insert_at, 56 - 0, 57 - array($panel_phid)); 58 - } else { 59 - $new_column_phids = array(0 => $panel_phid); 60 - } 61 - 62 - $panel_location_grid[$column_id] = $new_column_phids; 63 - $layout_config->setPanelLocations($panel_location_grid); 64 - $dashboard->setLayoutConfigFromObject($layout_config); 65 - $dashboard->save(); 66 - 67 - return id(new AphrontAjaxResponse())->setContent(''); 68 - } 69 - 70 - }
+43 -2
src/applications/dashboard/controller/dashboard/PhabricatorDashboardAdjustController.php
··· 39 39 } 40 40 41 41 $this->panelKey = $panel_key; 42 - } else { 43 - $panel_ref = null; 44 42 } 45 43 46 44 $column_key = $request->getStr('columnKey'); ··· 52 50 $this->columnKey = $column_key; 53 51 } 54 52 53 + $after_ref = null; 54 + $after_key = $request->getStr('afterKey'); 55 + if (strlen($after_key)) { 56 + $after_ref = $ref_list->getPanelRef($after_key); 57 + if (!$after_ref) { 58 + return new Aphront404Response(); 59 + } 60 + } 61 + 55 62 switch ($request->getURIData('op')) { 56 63 case 'add': 57 64 return $this->handleAddRequest($dashboard, $done_uri); ··· 60 67 return new Aphront404Response(); 61 68 } 62 69 return $this->handleRemoveRequest($dashboard, $panel_ref, $done_uri); 70 + case 'move': 71 + return $this->handleMoveRequest($dashboard, $panel_ref, $after_ref); 63 72 } 64 73 } 65 74 ··· 191 200 ->addCancelButton($done_uri) 192 201 ->addSubmitButton(pht('Remove Panel')); 193 202 } 203 + 204 + private function handleMoveRequest( 205 + PhabricatorDashboard $dashboard, 206 + PhabricatorDashboardPanelRef $panel_ref, 207 + PhabricatorDashboardPanelRef $after_ref = null) { 208 + 209 + $request = $this->getRequest(); 210 + $request->validateCSRF(); 211 + $viewer = $this->getViewer(); 212 + 213 + $xactions = array(); 214 + 215 + $ref_list = clone $dashboard->getPanelRefList(); 216 + $ref_list->movePanelRef($panel_ref, $this->columnKey, $after_ref); 217 + $new_panels = $ref_list->toDictionary(); 218 + 219 + $xactions[] = $dashboard->getApplicationTransactionTemplate() 220 + ->setTransactionType( 221 + PhabricatorDashboardPanelsTransaction::TRANSACTIONTYPE) 222 + ->setNewValue($new_panels); 223 + 224 + $editor = $dashboard->getApplicationTransactionEditor() 225 + ->setActor($viewer) 226 + ->setContentSourceFromRequest($request) 227 + ->setContinueOnNoEffect(true) 228 + ->setContinueOnMissingFields(true); 229 + 230 + $editor->applyTransactions($dashboard, $xactions); 231 + 232 + return id(new AphrontAjaxResponse())->setContent(array()); 233 + } 234 + 194 235 195 236 private function newEditDialog() { 196 237 return $this->newDialog()
+2 -2
src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php
··· 280 280 if ($panel) { 281 281 $box->setMetadata( 282 282 array( 283 - 'objectPHID' => $panel->getPHID(), 283 + 'panelKey' => $this->getPanelKey(), 284 284 )); 285 285 } 286 286 287 - return phutil_tag_div('dashboard-pane', $box); 287 + return $box; 288 288 } 289 289 290 290
+7 -2
src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php
··· 111 111 } 112 112 113 113 if ($is_editable) { 114 + $params = array( 115 + 'contextPHID' => $dashboard->getPHID(), 116 + ); 117 + $move_uri = new PhutilURI('/dashboard/adjust/move/', $params); 118 + 114 119 Javelin::initBehavior( 115 120 'dashboard-move-panels', 116 121 array( 117 - 'dashboardID' => $dashboard_id, 118 - 'moveURI' => '/dashboard/movepanel/'.$dashboard->getID().'/', 122 + 'dashboardNodeID' => $dashboard_id, 123 + 'moveURI' => (string)$move_uri, 119 124 )); 120 125 } 121 126
+6
src/applications/dashboard/layoutconfig/PhabricatorDashboardColumn.php
··· 25 25 return $this->classes; 26 26 } 27 27 28 + public function setPanelRefs(array $refs) { 29 + assert_instances_of($refs, 'PhabricatorDashboardPanelRef'); 30 + $this->refs = $refs; 31 + return $this; 32 + } 33 + 28 34 public function addPanelRef(PhabricatorDashboardPanelRef $ref) { 29 35 $this->refs[] = $ref; 30 36 return $this;
+37
src/applications/dashboard/layoutconfig/PhabricatorDashboardPanelRefList.php
··· 111 111 return null; 112 112 } 113 113 114 + public function movePanelRef( 115 + PhabricatorDashboardPanelRef $target, 116 + $column_key, 117 + PhabricatorDashboardPanelRef $after = null) { 118 + 119 + $target->setColumnKey($column_key); 120 + 121 + $results = array(); 122 + 123 + if (!$after) { 124 + $results[] = $target; 125 + } 126 + 127 + foreach ($this->refs as $ref) { 128 + if ($ref->getPanelKey() === $target->getPanelKey()) { 129 + continue; 130 + } 131 + 132 + $results[] = $ref; 133 + 134 + if ($after) { 135 + if ($ref->getPanelKey() === $after->getPanelKey()) { 136 + $results[] = $target; 137 + } 138 + } 139 + } 140 + 141 + $this->refs = $results; 142 + 143 + $column_map = mgroup($results, 'getColumnKey'); 144 + foreach ($this->columns as $column_key => $column) { 145 + $column->setPanelRefs(idx($column_map, $column_key, array())); 146 + } 147 + 148 + return $ref; 149 + } 150 + 114 151 private function newPanelKey() { 115 152 return Filesystem::readRandomCharacters(8); 116 153 }
-5
webroot/rsrc/css/phui/object-item/phui-oi-list-view.css
··· 611 611 border-top: none; 612 612 } 613 613 614 - .dashboard-pane .phui-oi-empty .phui-info-view { 615 - border: none; 616 - margin: 0; 617 - } 618 - 619 614 .device-desktop .aphront-multi-column-fluid .aphront-multi-column-2-up 620 615 .aphront-multi-column-column-outer.third .phui-oi-col2 { 621 616 display: none;
+11 -34
webroot/rsrc/js/application/dashboard/behavior-dashboard-move-panels.js
··· 33 33 list.lock(); 34 34 JX.DOM.alterClass(item, 'drag-sending', true); 35 35 36 - var item_phid = JX.Stratcom.getData(item).objectPHID; 37 36 var data = { 38 - objectPHID: item_phid, 39 - columnID: JX.Stratcom.getData(list.getRootNode()).columnID 37 + panelKey: JX.Stratcom.getData(item).panelKey, 38 + columnKey: JX.Stratcom.getData(list.getRootNode()).columnKey 40 39 }; 41 40 42 - var after_phid = null; 43 - var items = finditems(list.getRootNode()); 44 41 if (after) { 45 - after_phid = JX.Stratcom.getData(after).objectPHID; 46 - data.afterPHID = after_phid; 47 - } 48 - var ii; 49 - var ii_item; 50 - var ii_item_phid; 51 - var ii_prev_item_phid = null; 52 - var before_phid = null; 53 - for (ii = 0; ii < items.length; ii++) { 54 - ii_item = items[ii]; 55 - ii_item_phid = JX.Stratcom.getData(ii_item).objectPHID; 56 - if (ii_item_phid == item_phid) { 57 - // skip the item we just dropped 58 - continue; 42 + var after_data = JX.Stratcom.getData(after); 43 + if (after_data.panelKey) { 44 + data.afterKey = after_data.panelKey; 59 45 } 60 - // note this handles when there is no after phid - we are at the top of 61 - // the list - quite nicely 62 - if (ii_prev_item_phid == after_phid) { 63 - before_phid = ii_item_phid; 64 - break; 65 - } 66 - ii_prev_item_phid = ii_item_phid; 67 - } 68 - if (before_phid) { 69 - data.beforePHID = before_phid; 70 46 } 71 47 72 48 var workflow = new JX.Workflow(config.moveURI, data) ··· 77 53 workflow.start(); 78 54 } 79 55 56 + var dashboard_node = JX.$(config.dashboardNodeID); 57 + 80 58 var lists = []; 59 + var cols = JX.DOM.scry(dashboard_node, 'div', 'dashboard-column'); 60 + 81 61 var ii; 82 - var cols = JX.DOM.scry(JX.$(config.dashboardID), 'div', 'dashboard-column'); 83 - var col = null; 84 - 85 62 for (ii = 0; ii < cols.length; ii++) { 86 - col = cols[ii]; 63 + var col = cols[ii]; 87 64 var list = new JX.DraggableList(itemSigil, col) 88 65 .setFindItemsHandler(JX.bind(null, finditems, col)) 89 66 .setCanDragX(true); 90 67 91 68 list.listen('didSend', JX.bind(list, onupdate, col)); 92 69 list.listen('didReceive', JX.bind(list, onupdate, col)); 93 - 94 70 list.listen('didDrop', JX.bind(null, ondrop, list)); 95 71 96 72 lists.push(list); 73 + 97 74 markcolempty(col, finditems(col).length === 0); 98 75 } 99 76