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 @@ -4949,6 +4949,7 @@ 'PhabricatorWeekStartDaySetting' => 'applications/settings/setting/PhabricatorWeekStartDaySetting.php', 'PhabricatorWildConfigType' => 'applications/config/type/PhabricatorWildConfigType.php', 'PhabricatorWordPressAuthProvider' => 'applications/auth/provider/PhabricatorWordPressAuthProvider.php', + 'PhabricatorWorkboardViewState' => 'applications/project/state/PhabricatorWorkboardViewState.php', 'PhabricatorWorker' => 'infrastructure/daemon/workers/PhabricatorWorker.php', 'PhabricatorWorkerActiveTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php', 'PhabricatorWorkerActiveTaskQuery' => 'infrastructure/daemon/workers/query/PhabricatorWorkerActiveTaskQuery.php', @@ -11356,6 +11357,7 @@ 'PhabricatorWeekStartDaySetting' => 'PhabricatorSelectSetting', 'PhabricatorWildConfigType' => 'PhabricatorJSONConfigType', 'PhabricatorWordPressAuthProvider' => 'PhabricatorOAuth2AuthProvider', + 'PhabricatorWorkboardViewState' => 'Phobject', 'PhabricatorWorker' => 'Phobject', 'PhabricatorWorkerActiveTask' => 'PhabricatorWorkerTask', 'PhabricatorWorkerActiveTaskQuery' => 'PhabricatorWorkerTaskQuery', diff --git a/src/applications/project/controller/PhabricatorProjectBoardController.php b/src/applications/project/controller/PhabricatorProjectBoardController.php --- a/src/applications/project/controller/PhabricatorProjectBoardController.php +++ b/src/applications/project/controller/PhabricatorProjectBoardController.php @@ -1,4 +1,25 @@ viewState === null) { + $this->viewState = $this->newViewState(); + } + + return $this->viewState; + } + + final private function newViewState() { + $project = $this->getProject(); + $request = $this->getRequest(); + + return id(new PhabricatorWorkboardViewState()) + ->setProject($project) + ->readFromRequest($request); + } + +} 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 @@ -5,10 +5,6 @@ const BATCH_EDIT_ALL = 'all'; - private $queryKey; - private $sortKey; - private $showHidden; - public function shouldAllowPublic() { return true; } @@ -22,10 +18,8 @@ } $project = $this->getProject(); - - $this->readRequestState(); - - $board_uri = $this->getApplicationURI('board/'.$project->getID().'/'); + $state = $this->getViewState(); + $board_uri = $project->getWorkboardURI(); $search_engine = id(new ManiphestTaskSearchEngine()) ->setViewer($viewer) @@ -51,24 +45,15 @@ ->addSubmitButton(pht('Apply Filter')) ->addCancelButton($board_uri); } - return id(new AphrontRedirectResponse())->setURI( - $this->getURIWithState( - $search_engine->getQueryResultsPageURI($saved->getQueryKey()))); - } - - $query_key = $this->getDefaultFilter($project); - $request_query = $request->getStr('filter'); - if (strlen($request_query)) { - $query_key = $request_query; - } + $query_key = $saved->getQueryKey(); + $results_uri = $search_engine->getQueryResultsPageURI($query_key); + $results_uri = $state->newURI($results_uri); - $uri_query = $request->getURIData('queryKey'); - if (strlen($uri_query)) { - $query_key = $uri_query; + return id(new AphrontRedirectResponse())->setURI($results_uri); } - $this->queryKey = $query_key; + $query_key = $state->getQueryKey(); $custom_query = null; if ($search_engine->isBuiltinQuery($query_key)) { @@ -260,7 +245,7 @@ } if (!$batch_tasks) { - $cancel_uri = $this->getURIWithState($board_uri); + $cancel_uri = $state->newWorkboardURI(); return $this->newDialog() ->setTitle(pht('No Editable Tasks')) ->appendParagraph( @@ -308,7 +293,7 @@ } $move_tasks = array_select_keys($tasks, $move_task_phids); - $cancel_uri = $this->getURIWithState($board_uri); + $cancel_uri = $state->newWorkboardURI(); if (!$move_tasks) { return $this->newDialog() @@ -504,7 +489,7 @@ $column_phids = array(); $visible_phids = array(); foreach ($columns as $column) { - if (!$this->showHidden) { + if (!$state->getShowHidden()) { if ($column->isHidden()) { continue; } @@ -649,7 +634,7 @@ ); } - $order_key = $this->sortKey; + $order_key = $state->getOrder(); $ordering_map = PhabricatorProjectColumnOrder::getEnabledOrders(); $ordering = id(clone $ordering_map[$order_key]) @@ -683,7 +668,7 @@ 'pointsEnabled' => ManiphestTaskPoints::getIsEnabled(), 'boardPHID' => $project->getPHID(), - 'order' => $this->sortKey, + 'order' => $state->getOrder(), 'orders' => $order_maps, 'headers' => $headers, 'headerKeys' => $header_keys, @@ -701,7 +686,7 @@ $sort_menu = $this->buildSortMenu( $viewer, $project, - $this->sortKey, + $state->getOrder(), $ordering_map); $filter_menu = $this->buildFilterMenu( @@ -711,7 +696,7 @@ $search_engine, $query_key); - $manage_menu = $this->buildManageMenu($project, $this->showHidden); + $manage_menu = $this->buildManageMenu($project, $state->getShowHidden()); $header_link = phutil_tag( 'a', @@ -775,54 +760,14 @@ return $page; } - private function readRequestState() { - $request = $this->getRequest(); - $project = $this->getProject(); - - $this->showHidden = $request->getBool('hidden'); - - $sort_key = $this->getDefaultSort($project); - - $request_sort = $request->getStr('order'); - if ($this->isValidSort($request_sort)) { - $sort_key = $request_sort; - } - - $this->sortKey = $sort_key; - } - - private function getDefaultSort(PhabricatorProject $project) { - $default_sort = $project->getDefaultWorkboardSort(); - - if ($this->isValidSort($default_sort)) { - return $default_sort; - } - - return PhabricatorProjectColumnNaturalOrder::ORDERKEY; - } - - private function getDefaultFilter(PhabricatorProject $project) { - $default_filter = $project->getDefaultWorkboardFilter(); - - if (strlen($default_filter)) { - return $default_filter; - } - - return 'open'; - } - - private function isValidSort($sort) { - $map = PhabricatorProjectColumnOrder::getEnabledOrders(); - return isset($map[$sort]); - } - private function buildSortMenu( PhabricatorUser $viewer, PhabricatorProject $project, $sort_key, array $ordering_map) { - $base_uri = $this->getURIWithState(); + $state = $this->getViewState(); + $base_uri = $state->newWorkboardURI(); $items = array(); foreach ($ordering_map as $key => $ordering) { @@ -997,6 +942,7 @@ $request = $this->getRequest(); $viewer = $request->getUser(); + $state = $this->getViewState(); $id = $project->getID(); @@ -1026,12 +972,12 @@ ->setWorkflow(true); if ($show_hidden) { - $hidden_uri = $this->getURIWithState() + $hidden_uri = $state->newWorkboardURI() ->removeQueryParam('hidden'); $hidden_icon = 'fa-eye-slash'; $hidden_text = pht('Hide Hidden Columns'); } else { - $hidden_uri = $this->getURIWithState() + $hidden_uri = $state->newWorkboardURI() ->replaceQueryParam('hidden', 'true'); $hidden_icon = 'fa-eye'; $hidden_text = pht('Show Hidden Columns'); @@ -1307,41 +1253,11 @@ * @return PhutilURI URI with state parameters. */ private function getURIWithState($base = null, $force = false) { - $project = $this->getProject(); - if ($base === null) { - $base = $this->getRequest()->getPath(); - } - - $base = new PhutilURI($base); - - if ($force || ($this->sortKey != $this->getDefaultSort($project))) { - if ($this->sortKey !== null) { - $base->replaceQueryParam('order', $this->sortKey); - } else { - $base->removeQueryParam('order'); - } - } else { - $base->removeQueryParam('order'); - } - - if ($force || ($this->queryKey != $this->getDefaultFilter($project))) { - if ($this->queryKey !== null) { - $base->replaceQueryParam('filter', $this->queryKey); - } else { - $base->removeQueryParam('filter'); - } - } else { - $base->removeQueryParam('filter'); - } - - if ($this->showHidden) { - $base->replaceQueryParam('hidden', 'true'); - } else { - $base->removeQueryParam('hidden'); + $base = $this->getProject()->getWorkboardURI(); } - return $base; + return $this->getViewState()->newURI($base, $force); } private function buildInitializeContent(PhabricatorProject $project) { diff --git a/src/applications/project/state/PhabricatorWorkboardViewState.php b/src/applications/project/state/PhabricatorWorkboardViewState.php new file mode 100644 --- /dev/null +++ b/src/applications/project/state/PhabricatorWorkboardViewState.php @@ -0,0 +1,150 @@ +project = $project; + return $this; + } + + public function getProject() { + return $this->project; + } + + public function readFromRequest(AphrontRequest $request) { + if ($request->getExists('hidden')) { + $this->requestState['hidden'] = $request->getBool('hidden'); + } + + if ($request->getExists('order')) { + $this->requestState['order'] = $request->getStr('order'); + } + + // On some pathways, the search engine query key may be specified with + // either a "?filter=X" query parameter or with a "/query/X/" URI + // component. If both are present, the URI component is controlling. + + // In particular, the "queryKey" URI parameter is used by + // "buildSavedQueryFromRequest()" when we are building custom board filters + // by invoking SearchEngine code. + + if ($request->getExists('filter')) { + $this->requestState['filter'] = $request->getStr('filter'); + } + + if (strlen($request->getURIData('queryKey'))) { + $this->requestState['filter'] = $request->getURIData('queryKey'); + } + + return $this; + } + + public function newWorkboardURI($path = null) { + $project = $this->getProject(); + $uri = urisprintf('%p%p', $project->getWorkboardURI(), $path); + return $this->newURI($uri); + } + + public function newURI($path, $force = false) { + $project = $this->getProject(); + $uri = new PhutilURI($path); + + $request_order = $this->getOrder(); + $default_order = $this->getDefaultOrder(); + if ($force || ($request_order !== $default_order)) { + $request_value = idx($this->requestState, 'order'); + if ($request_value !== null) { + $uri->replaceQueryParam('order', $request_value); + } else { + $uri->removeQueryParam('order'); + } + } else { + $uri->removeQueryParam('order'); + } + + $request_query = $this->getQueryKey(); + $default_query = $this->getDefaultQueryKey(); + if ($force || ($request_query !== $default_query)) { + $request_value = idx($this->requestState, 'filter'); + if ($request_value !== null) { + $uri->replaceQueryParam('filter', $request_value); + } else { + $uri->removeQueryParam('filter'); + } + } else { + $uri->removeQueryParam('filter'); + } + + if ($this->getShowHidden()) { + $uri->replaceQueryParam('hidden', 'true'); + } else { + $uri->removeQueryParam('hidden'); + } + + return $uri; + } + + public function getShowHidden() { + $request_show = idx($this->requestState, 'hidden'); + + if ($request_show !== null) { + return $request_show; + } + + return false; + } + + public function getOrder() { + $request_order = idx($this->requestState, 'order'); + if ($request_order !== null) { + if ($this->isValidOrder($request_order)) { + return $request_order; + } + } + + return $this->getDefaultOrder(); + } + + public function getQueryKey() { + $request_query = idx($this->requestState, 'filter'); + if (strlen($request_query)) { + return $request_query; + } + + return $this->getDefaultQueryKey(); + } + + private function isValidOrder($order) { + $map = PhabricatorProjectColumnOrder::getEnabledOrders(); + return isset($map[$order]); + } + + private function getDefaultOrder() { + $project = $this->getProject(); + + $default_order = $project->getDefaultWorkboardSort(); + + if ($this->isValidOrder($default_order)) { + return $default_order; + } + + return PhabricatorProjectColumnNaturalOrder::ORDERKEY; + } + + private function getDefaultQueryKey() { + $project = $this->getProject(); + + $default_query = $project->getDefaultWorkboardFilter(); + + if (strlen($default_query)) { + return $default_query; + } + + return 'open'; + } + +}