Add "Move Left" and "Move Right" to dashboard tab panels
Summary: Depends on D20474. Ref T13272. Provide an easy way to rearrange tabs on a tab panel, by moving them left or right from the context menu. Test Plan: Moved tabs left and right. Tried to move them off the end of the tab list, no luck. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13272 Differential Revision: https://secure.phabricator.com/D20475
This commit is contained in:
		| @@ -383,6 +383,15 @@ final class AphrontRequest extends Phobject { | |||||||
|     return $this->validateCSRF(); |     return $this->validateCSRF(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   public function hasCSRF() { | ||||||
|  |     try { | ||||||
|  |       $this->validateCSRF(); | ||||||
|  |       return true; | ||||||
|  |     } catch (AphrontMalformedRequestException $ex) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   public function isFormOrHisecPost() { |   public function isFormOrHisecPost() { | ||||||
|     $post = $this->getExists(self::TYPE_FORM) && |     $post = $this->getExists(self::TYPE_FORM) && | ||||||
|             $this->isHTTPPost(); |             $this->isHTTPPost(); | ||||||
|   | |||||||
| @@ -140,7 +140,7 @@ final class PhabricatorDashboardPanelTabsController | |||||||
|       case 'remove': |       case 'remove': | ||||||
|         return $this->handleRemoveOperation($panel, $target, $cancel_uri); |         return $this->handleRemoveOperation($panel, $target, $cancel_uri); | ||||||
|       case 'move': |       case 'move': | ||||||
|         break; |         return $this->handleMoveOperation($panel, $target, $after, $cancel_uri); | ||||||
|       case 'rename': |       case 'rename': | ||||||
|         return $this->handleRenameOperation($panel, $target, $cancel_uri); |         return $this->handleRenameOperation($panel, $target, $cancel_uri); | ||||||
|     } |     } | ||||||
| @@ -298,6 +298,89 @@ final class PhabricatorDashboardPanelTabsController | |||||||
|       ->addSubmitButton(pht('Rename Tab')); |       ->addSubmitButton(pht('Rename Tab')); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   private function handleMoveOperation( | ||||||
|  |     PhabricatorDashboardPanel $panel, | ||||||
|  |     $target, | ||||||
|  |     $after, | ||||||
|  |     $cancel_uri) { | ||||||
|  |     $request = $this->getRequest(); | ||||||
|  |     $viewer = $this->getViewer(); | ||||||
|  |  | ||||||
|  |     $move = $request->getStr('move'); | ||||||
|  |  | ||||||
|  |     $impl = $panel->getImplementation(); | ||||||
|  |     $old_config = $impl->getPanelConfiguration($panel); | ||||||
|  |  | ||||||
|  |     $is_next = ($move === 'next'); | ||||||
|  |     if ($target === $after) { | ||||||
|  |       return $this->newDialog() | ||||||
|  |         ->setTitle(pht('Impossible!')) | ||||||
|  |         ->appendParagraph( | ||||||
|  |           pht( | ||||||
|  |             'You can not move a tab relative to itself.')) | ||||||
|  |         ->addCancelButton($cancel_uri); | ||||||
|  |     } else if ($is_next && ((string)last_key($old_config) === $target)) { | ||||||
|  |       return $this->newDialog() | ||||||
|  |         ->setTitle(pht('Impossible!')) | ||||||
|  |         ->appendParagraph( | ||||||
|  |           pht( | ||||||
|  |             'This is already the last tab. It can not move any farther to '. | ||||||
|  |             'the right.')) | ||||||
|  |         ->addCancelButton($cancel_uri); | ||||||
|  |     } else if ((string)head_key($old_config) === $target) { | ||||||
|  |       return $this->newDialog() | ||||||
|  |         ->setTitle(pht('Impossible!')) | ||||||
|  |         ->appendParagraph( | ||||||
|  |           pht( | ||||||
|  |             'This is already the first tab. It can not move any farther to '. | ||||||
|  |             'the left.')) | ||||||
|  |         ->addCancelButton($cancel_uri); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if ($request->hasCSRF()) { | ||||||
|  |       $new_config = array(); | ||||||
|  |       foreach ($old_config as $old_key => $old_spec) { | ||||||
|  |         $old_key = (string)$old_key; | ||||||
|  |  | ||||||
|  |         $is_after = ($old_key === $after); | ||||||
|  |  | ||||||
|  |         if (!$is_after) { | ||||||
|  |           if ($old_key === $target) { | ||||||
|  |             continue; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($is_after && !$is_next) { | ||||||
|  |           $new_config[$target] = $old_config[$target]; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $new_config[$old_key] = $old_spec; | ||||||
|  |  | ||||||
|  |         if ($is_after && $is_next) { | ||||||
|  |           $new_config[$target] = $old_config[$target]; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       $this->writePanelConfig($panel, $new_config); | ||||||
|  |  | ||||||
|  |       return id(new AphrontRedirectResponse())->setURI($cancel_uri); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if ($is_next) { | ||||||
|  |       $prompt = pht('Move this tab to the right?'); | ||||||
|  |     } else { | ||||||
|  |       $prompt = pht('Move this tab to the left?'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return $this->newEditDialog() | ||||||
|  |       ->setTitle(pht('Move Tab')) | ||||||
|  |       ->addHiddenInput('target', $target) | ||||||
|  |       ->addHiddenInput('after', $after) | ||||||
|  |       ->addHiddenInput('move', $move) | ||||||
|  |       ->appendParagraph($prompt) | ||||||
|  |       ->addCancelButton($cancel_uri) | ||||||
|  |       ->addSubmitButton(pht('Move Tab')); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   private function writePanelConfig( |   private function writePanelConfig( | ||||||
|     PhabricatorDashboardPanel $panel, |     PhabricatorDashboardPanel $panel, | ||||||
|   | |||||||
| @@ -87,7 +87,15 @@ final class PhabricatorDashboardTabsPanelType | |||||||
|  |  | ||||||
|     $selected = 0; |     $selected = 0; | ||||||
|  |  | ||||||
|     $last_idx = null; |     $key_list = array_keys($config); | ||||||
|  |  | ||||||
|  |     $next_keys = array(); | ||||||
|  |     $prev_keys = array(); | ||||||
|  |     for ($ii = 0; $ii < count($key_list); $ii++) { | ||||||
|  |       $next_keys[$key_list[$ii]] = idx($key_list, $ii + 1); | ||||||
|  |       $prev_keys[$key_list[$ii]] = idx($key_list, $ii - 1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     foreach ($config as $idx => $tab_spec) { |     foreach ($config as $idx => $tab_spec) { | ||||||
|       $panel_id = idx($tab_spec, 'panelID'); |       $panel_id = idx($tab_spec, 'panelID'); | ||||||
|       $subpanel = idx($panels, $panel_id); |       $subpanel = idx($panels, $panel_id); | ||||||
| @@ -145,6 +153,42 @@ final class PhabricatorDashboardTabsPanelType | |||||||
|             ->setHref($rename_tab_uri) |             ->setHref($rename_tab_uri) | ||||||
|             ->setWorkflow(true)); |             ->setWorkflow(true)); | ||||||
|  |  | ||||||
|  |         $move_uri = urisprintf('/dashboard/panel/tabs/%d/move/', $id); | ||||||
|  |  | ||||||
|  |         $prev_key = $prev_keys[$idx]; | ||||||
|  |         $prev_params = array( | ||||||
|  |           'target' => $idx, | ||||||
|  |           'after' => $prev_key, | ||||||
|  |           'move' => 'prev', | ||||||
|  |           'contextPHID' => $context_phid, | ||||||
|  |         ); | ||||||
|  |         $prev_uri = new PhutilURI($move_uri, $prev_params); | ||||||
|  |  | ||||||
|  |         $next_key = $next_keys[$idx]; | ||||||
|  |         $next_params = array( | ||||||
|  |           'target' => $idx, | ||||||
|  |           'after' => $next_key, | ||||||
|  |           'move' => 'next', | ||||||
|  |           'contextPHID' => $context_phid, | ||||||
|  |         ); | ||||||
|  |         $next_uri = new PhutilURI($move_uri, $next_params); | ||||||
|  |  | ||||||
|  |         $dropdown_menu->addAction( | ||||||
|  |           id(new PhabricatorActionView()) | ||||||
|  |             ->setName(pht('Move Tab Left')) | ||||||
|  |             ->setIcon('fa-chevron-left') | ||||||
|  |             ->setHref($prev_uri) | ||||||
|  |             ->setWorkflow(true) | ||||||
|  |             ->setDisabled(($prev_key === null) || !$can_edit)); | ||||||
|  |  | ||||||
|  |         $dropdown_menu->addAction( | ||||||
|  |           id(new PhabricatorActionView()) | ||||||
|  |             ->setName(pht('Move Tab Right')) | ||||||
|  |             ->setIcon('fa-chevron-right') | ||||||
|  |             ->setHref($next_uri) | ||||||
|  |             ->setWorkflow(true) | ||||||
|  |             ->setDisabled(($next_key === null) || !$can_edit)); | ||||||
|  |  | ||||||
|         $dropdown_menu->addAction( |         $dropdown_menu->addAction( | ||||||
|           id(new PhabricatorActionView()) |           id(new PhabricatorActionView()) | ||||||
|             ->setName(pht('Remove Tab')) |             ->setName(pht('Remove Tab')) | ||||||
| @@ -177,15 +221,16 @@ final class PhabricatorDashboardTabsPanelType | |||||||
|       } |       } | ||||||
|  |  | ||||||
|       $list->addMenuItem($tab_view); |       $list->addMenuItem($tab_view); | ||||||
|  |  | ||||||
|       $last_idx = $idx; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     if ($is_edit) { |     if ($is_edit) { | ||||||
|       $actions = id(new PhabricatorActionListView()) |       $actions = id(new PhabricatorActionListView()) | ||||||
|         ->setViewer($viewer); |         ->setViewer($viewer); | ||||||
|  |  | ||||||
|       $add_last_uri = clone $add_uri; |       $add_last_uri = clone $add_uri; | ||||||
|  |  | ||||||
|  |       $last_idx = last_key($config); | ||||||
|       if ($last_idx) { |       if ($last_idx) { | ||||||
|         $add_last_uri->replaceQueryParam('after', $last_idx); |         $add_last_uri->replaceQueryParam('after', $last_idx); | ||||||
|       } |       } | ||||||
|   | |||||||
| @@ -10,12 +10,7 @@ final class PhabricatorNotificationClearController | |||||||
|     if ($request->isDialogFormPost()) { |     if ($request->isDialogFormPost()) { | ||||||
|       $should_clear = true; |       $should_clear = true; | ||||||
|     } else { |     } else { | ||||||
|       try { |       $should_clear = $request->hasCSRF(); | ||||||
|         $request->validateCSRF(); |  | ||||||
|         $should_clear = true; |  | ||||||
|       } catch (AphrontMalformedRequestException $ex) { |  | ||||||
|         $should_clear = false; |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if ($should_clear) { |     if ($should_clear) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 epriestley
					epriestley