mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 00:32:42 +01:00
Move workboard "filter" workflow to a separate controller
Summary: Depends on D20629. Ref T4900. Currently, the "Advanced Filter..." workflow on workboards (where you build a custom query) is inline in the main board controller. This is because the filter flow depends on some of the board view state: we want to start with the current filter applied to the board, and preserve other state after you change the filter. Now that `ViewState` can handle state management, we can separate this stuff out pretty easily. Test Plan: - Changed filters on a board. - Applied a custom filter to a board. - Changed the ordering of a board, then applied a custom filter. Verified "Cancel" and "Apply Filter" both preserve the order state. - Changed the ordering of a board, then applied a custom filter, intentionally making a mistake in configuring the filter by entering an invalid date. Saw a dialog with an error. After correcting the error, saw state preserved properly. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T4900 Differential Revision: https://secure.phabricator.com/D20632
This commit is contained in:
parent
9e096cd274
commit
577020aea9
7 changed files with 131 additions and 62 deletions
|
@ -4160,6 +4160,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectBoardController' => 'applications/project/controller/PhabricatorProjectBoardController.php',
|
||||
'PhabricatorProjectBoardDefaultController' => 'applications/project/controller/PhabricatorProjectBoardDefaultController.php',
|
||||
'PhabricatorProjectBoardDisableController' => 'applications/project/controller/PhabricatorProjectBoardDisableController.php',
|
||||
'PhabricatorProjectBoardFilterController' => 'applications/project/controller/PhabricatorProjectBoardFilterController.php',
|
||||
'PhabricatorProjectBoardImportController' => 'applications/project/controller/PhabricatorProjectBoardImportController.php',
|
||||
'PhabricatorProjectBoardManageController' => 'applications/project/controller/PhabricatorProjectBoardManageController.php',
|
||||
'PhabricatorProjectBoardReorderController' => 'applications/project/controller/PhabricatorProjectBoardReorderController.php',
|
||||
|
@ -10424,6 +10425,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectBoardController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectBoardDefaultController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectBoardDisableController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectBoardFilterController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectBoardImportController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectBoardManageController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectBoardReorderController' => 'PhabricatorProjectBoardController',
|
||||
|
|
|
@ -66,7 +66,6 @@ final class PhabricatorProjectApplication extends PhabricatorApplication {
|
|||
'subprojects/(?P<id>[1-9]\d*)/'
|
||||
=> 'PhabricatorProjectSubprojectsController',
|
||||
'board/(?P<id>[1-9]\d*)/'.
|
||||
'(?P<filter>filter/)?'.
|
||||
'(?:query/(?P<queryKey>[^/]+)/)?'
|
||||
=> 'PhabricatorProjectBoardViewController',
|
||||
'move/(?P<id>[1-9]\d*)/' => 'PhabricatorProjectMoveController',
|
||||
|
@ -92,6 +91,8 @@ final class PhabricatorProjectApplication extends PhabricatorApplication {
|
|||
=> 'PhabricatorProjectBoardBackgroundController',
|
||||
'default/(?P<target>[^/]+)/'
|
||||
=> 'PhabricatorProjectBoardDefaultController',
|
||||
'filter/(?:query/(?P<queryKey>[^/]+)/)?'
|
||||
=> 'PhabricatorProjectBoardFilterController',
|
||||
),
|
||||
'column/' => array(
|
||||
'remove/(?P<id>\d+)/' =>
|
||||
|
|
|
@ -22,7 +22,7 @@ abstract class PhabricatorProjectBoardController
|
|||
->readFromRequest($request);
|
||||
}
|
||||
|
||||
final protected function newBoardDialog() {
|
||||
final protected function newWorkboardDialog() {
|
||||
$dialog = $this->newDialog();
|
||||
|
||||
$state = $this->getViewState();
|
||||
|
|
|
@ -72,7 +72,7 @@ final class PhabricatorProjectBoardDefaultController
|
|||
return id(new AphrontRedirectResponse())->setURI($board_uri);
|
||||
}
|
||||
|
||||
return $this->newBoardDialog()
|
||||
return $this->newWorkboardDialog()
|
||||
->setTitle($title)
|
||||
->appendChild($body)
|
||||
->addCancelButton($board_uri)
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectBoardFilterController
|
||||
extends PhabricatorProjectBoardController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
$response = $this->loadProject();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$project = $this->getProject();
|
||||
$state = $this->getViewState();
|
||||
$board_uri = $state->newWorkboardURI();
|
||||
|
||||
$search_engine = $state->getSearchEngine();
|
||||
|
||||
$is_submit = $request->isFormPost();
|
||||
|
||||
if ($is_submit) {
|
||||
$saved_query = $search_engine->buildSavedQueryFromRequest($request);
|
||||
$search_engine->saveQuery($saved_query);
|
||||
} else {
|
||||
$saved_query = $state->getSavedQuery();
|
||||
if (!$saved_query) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
}
|
||||
|
||||
$filter_form = id(new AphrontFormView())
|
||||
->setUser($viewer);
|
||||
|
||||
$search_engine->buildSearchForm($filter_form, $saved_query);
|
||||
|
||||
$errors = $search_engine->getErrors();
|
||||
|
||||
if ($is_submit && !$errors) {
|
||||
$query_key = $saved_query->getQueryKey();
|
||||
|
||||
$state->setQueryKey($query_key);
|
||||
$board_uri = $state->newWorkboardURI();
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($board_uri);
|
||||
}
|
||||
|
||||
return $this->newWorkboardDialog()
|
||||
->setWidth(AphrontDialogView::WIDTH_FULL)
|
||||
->setTitle(pht('Advanced Filter'))
|
||||
->appendChild($filter_form->buildLayoutView())
|
||||
->setErrors($errors)
|
||||
->addSubmitButton(pht('Apply Filter'))
|
||||
->addCancelButton($board_uri);
|
||||
}
|
||||
}
|
|
@ -21,68 +21,17 @@ final class PhabricatorProjectBoardViewController
|
|||
$state = $this->getViewState();
|
||||
$board_uri = $project->getWorkboardURI();
|
||||
|
||||
$search_engine = id(new ManiphestTaskSearchEngine())
|
||||
->setViewer($viewer)
|
||||
->setBaseURI($board_uri)
|
||||
->setIsBoardView(true);
|
||||
|
||||
if ($request->isFormPost()
|
||||
&& !$request->getBool('initialize')
|
||||
&& !$request->getStr('move')
|
||||
&& !$request->getStr('queryColumnID')) {
|
||||
$saved = $search_engine->buildSavedQueryFromRequest($request);
|
||||
$search_engine->saveQuery($saved);
|
||||
$filter_form = id(new AphrontFormView())
|
||||
->setUser($viewer);
|
||||
$search_engine->buildSearchForm($filter_form, $saved);
|
||||
if ($search_engine->getErrors()) {
|
||||
return $this->newDialog()
|
||||
->setWidth(AphrontDialogView::WIDTH_FULL)
|
||||
->setTitle(pht('Advanced Filter'))
|
||||
->appendChild($filter_form->buildLayoutView())
|
||||
->setErrors($search_engine->getErrors())
|
||||
->setSubmitURI($board_uri)
|
||||
->addSubmitButton(pht('Apply Filter'))
|
||||
->addCancelButton($board_uri);
|
||||
}
|
||||
|
||||
$query_key = $saved->getQueryKey();
|
||||
$results_uri = $search_engine->getQueryResultsPageURI($query_key);
|
||||
$results_uri = $state->newURI($results_uri);
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($results_uri);
|
||||
}
|
||||
|
||||
$search_engine = $state->getSearchEngine();
|
||||
$query_key = $state->getQueryKey();
|
||||
|
||||
$custom_query = null;
|
||||
if ($search_engine->isBuiltinQuery($query_key)) {
|
||||
$saved = $search_engine->buildSavedQueryFromBuiltin($query_key);
|
||||
} else {
|
||||
$saved = id(new PhabricatorSavedQueryQuery())
|
||||
->setViewer($viewer)
|
||||
->withQueryKeys(array($query_key))
|
||||
->executeOne();
|
||||
|
||||
if (!$saved) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$custom_query = $saved;
|
||||
$saved = $state->getSavedQuery();
|
||||
if (!$saved) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
if ($request->getURIData('filter')) {
|
||||
$filter_form = id(new AphrontFormView())
|
||||
->setUser($viewer);
|
||||
$search_engine->buildSearchForm($filter_form, $saved);
|
||||
|
||||
return $this->newDialog()
|
||||
->setWidth(AphrontDialogView::WIDTH_FULL)
|
||||
->setTitle(pht('Advanced Filter'))
|
||||
->appendChild($filter_form->buildLayoutView())
|
||||
->setSubmitURI($board_uri)
|
||||
->addSubmitButton(pht('Apply Filter'))
|
||||
->addCancelButton($board_uri);
|
||||
if ($saved->getID()) {
|
||||
$custom_query = $saved;
|
||||
} else {
|
||||
$custom_query = null;
|
||||
}
|
||||
|
||||
$task_query = $search_engine->buildQueryFromSavedQuery($saved);
|
||||
|
|
|
@ -3,8 +3,11 @@
|
|||
final class PhabricatorWorkboardViewState
|
||||
extends Phobject {
|
||||
|
||||
private $viewer;
|
||||
private $project;
|
||||
private $requestState = array();
|
||||
private $savedQuery;
|
||||
private $searchEngine;
|
||||
|
||||
public function setProject(PhabricatorProject $project) {
|
||||
$this->project = $project;
|
||||
|
@ -40,9 +43,62 @@ final class PhabricatorWorkboardViewState
|
|||
$this->requestState['filter'] = $request->getURIData('queryKey');
|
||||
}
|
||||
|
||||
$this->viewer = $request->getViewer();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getViewer() {
|
||||
return $this->viewer;
|
||||
}
|
||||
|
||||
public function getSavedQuery() {
|
||||
if ($this->savedQuery === null) {
|
||||
$this->savedQuery = $this->newSavedQuery();
|
||||
}
|
||||
|
||||
return $this->savedQuery;
|
||||
}
|
||||
|
||||
private function newSavedQuery() {
|
||||
$search_engine = $this->getSearchEngine();
|
||||
$query_key = $this->getQueryKey();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
if ($search_engine->isBuiltinQuery($query_key)) {
|
||||
$saved_query = $search_engine->buildSavedQueryFromBuiltin($query_key);
|
||||
} else {
|
||||
$saved_query = id(new PhabricatorSavedQueryQuery())
|
||||
->setViewer($viewer)
|
||||
->withQueryKeys(array($query_key))
|
||||
->executeOne();
|
||||
}
|
||||
|
||||
return $saved_query;
|
||||
}
|
||||
|
||||
public function getSearchEngine() {
|
||||
if ($this->searchEngine === null) {
|
||||
$this->searchEngine = $this->newSearchEngine();
|
||||
}
|
||||
|
||||
return $this->searchEngine;
|
||||
}
|
||||
|
||||
private function newSearchEngine() {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
// TODO: This URI is not fully state-preserving, because "SearchEngine"
|
||||
// does not preserve URI parameters when constructing some URIs at time of
|
||||
// writing.
|
||||
$board_uri = $this->getProject()->getWorkboardURI();
|
||||
|
||||
return id(new ManiphestTaskSearchEngine())
|
||||
->setViewer($viewer)
|
||||
->setBaseURI($board_uri)
|
||||
->setIsBoardView(true);
|
||||
}
|
||||
|
||||
public function newWorkboardURI($path = null) {
|
||||
$project = $this->getProject();
|
||||
$uri = urisprintf('%p%p', $project->getWorkboardURI(), $path);
|
||||
|
@ -118,6 +174,11 @@ final class PhabricatorWorkboardViewState
|
|||
return $this->getDefaultQueryKey();
|
||||
}
|
||||
|
||||
public function setQueryKey($query_key) {
|
||||
$this->requestState['filter'] = $query_key;
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function isValidOrder($order) {
|
||||
$map = PhabricatorProjectColumnOrder::getEnabledOrders();
|
||||
return isset($map[$order]);
|
||||
|
|
Loading…
Reference in a new issue