Page MenuHomePhabricator

D19366.diff
No OneTemporary

D19366.diff

diff --git a/src/applications/maniphest/query/ManiphestTaskQuery.php b/src/applications/maniphest/query/ManiphestTaskQuery.php
--- a/src/applications/maniphest/query/ManiphestTaskQuery.php
+++ b/src/applications/maniphest/query/ManiphestTaskQuery.php
@@ -26,6 +26,7 @@
private $closedEpochMin;
private $closedEpochMax;
private $closerPHIDs;
+ private $columnPHIDs;
private $status = 'status-any';
const STATUS_ANY = 'status-any';
@@ -213,6 +214,11 @@
return $this;
}
+ public function withColumnPHIDs(array $column_phids) {
+ $this->columnPHIDs = $column_phids;
+ return $this;
+ }
+
public function newResultObject() {
return new ManiphestTask();
}
@@ -442,6 +448,91 @@
$this->subtypes);
}
+
+ if ($this->columnPHIDs !== null) {
+ $viewer = $this->getViewer();
+
+ $columns = id(new PhabricatorProjectColumnQuery())
+ ->setParentQuery($this)
+ ->setViewer($viewer)
+ ->withPHIDs($this->columnPHIDs)
+ ->execute();
+ if (!$columns) {
+ throw new PhabricatorEmptyQueryException();
+ }
+
+ // We must do board layout before we move forward because the column
+ // positions may not yet exist otherwise. An example is that newly
+ // created tasks may not yet be positioned in the backlog column.
+
+ $projects = mpull($columns, 'getProject');
+ $projects = mpull($projects, null, 'getPHID');
+
+ // The board layout engine needs to know about every object that it's
+ // going to be asked to do layout for. For now, we're just doing layout
+ // on every object on the boards. In the future, we could do layout on a
+ // smaller set of objects by using the constraints on this Query. For
+ // example, if the caller is only asking for open tasks, we only need
+ // to do layout on open tasks.
+
+ // This fetches too many objects (every type of object tagged with the
+ // project, not just tasks). We could narrow it by querying the edge
+ // table on the Maniphest side, but there's currently no way to build
+ // that query with EdgeQuery.
+ $edge_query = id(new PhabricatorEdgeQuery())
+ ->withSourcePHIDs(array_keys($projects))
+ ->withEdgeTypes(
+ array(
+ PhabricatorProjectProjectHasObjectEdgeType::EDGECONST,
+ ));
+
+ $edge_query->execute();
+ $all_phids = $edge_query->getDestinationPHIDs();
+
+ // Since we overfetched PHIDs, filter out any non-tasks we got back.
+ foreach ($all_phids as $key => $phid) {
+ if (phid_get_type($phid) !== ManiphestTaskPHIDType::TYPECONST) {
+ unset($all_phids[$key]);
+ }
+ }
+
+ // If there are no tasks on the relevant boards, this query can't
+ // possibly hit anything so we're all done.
+ $task_phids = array_fuse($all_phids);
+ if (!$task_phids) {
+ throw new PhabricatorEmptyQueryException();
+ }
+
+ // We know everything we need to know, so perform board layout.
+ $engine = id(new PhabricatorBoardLayoutEngine())
+ ->setViewer($viewer)
+ ->setFetchAllBoards(true)
+ ->setBoardPHIDs(array_keys($projects))
+ ->setObjectPHIDs($task_phids)
+ ->executeLayout();
+
+ // Find the tasks that are in the constraint columns after board layout
+ // completes.
+ $select_phids = array();
+ foreach ($columns as $column) {
+ $in_column = $engine->getColumnObjectPHIDs(
+ $column->getProjectPHID(),
+ $column->getPHID());
+ foreach ($in_column as $phid) {
+ $select_phids[$phid] = $phid;
+ }
+ }
+
+ if (!$select_phids) {
+ throw new PhabricatorEmptyQueryException();
+ }
+
+ $where[] = qsprintf(
+ $conn,
+ 'task.phid IN (%Ls)',
+ $select_phids);
+ }
+
return $where;
}
diff --git a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php
--- a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php
+++ b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php
@@ -86,6 +86,10 @@
pht('Search for tasks with given subtypes.'))
->setDatasource(new ManiphestTaskSubtypeDatasource())
->setIsHidden($hide_subtypes),
+ id(new PhabricatorPHIDsSearchField())
+ ->setLabel(pht('Columns'))
+ ->setKey('columnPHIDs')
+ ->setAliases(array('column', 'columnPHID', 'columns')),
id(new PhabricatorSearchThreeStateField())
->setLabel(pht('Open Parents'))
->setKey('hasParents')
@@ -246,6 +250,10 @@
$query->withSubtaskIDs($map['subtaskIDs']);
}
+ if ($map['columnPHIDs']) {
+ $query->withColumnPHIDs($map['columnPHIDs']);
+ }
+
$group = idx($map, 'group');
$group = idx($this->getGroupValues(), $group);
if ($group) {
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
@@ -36,7 +36,8 @@
if ($request->isFormPost()
&& !$request->getBool('initialize')
- && !$request->getStr('move')) {
+ && !$request->getStr('move')
+ && !$request->getStr('queryColumnID')) {
$saved = $search_engine->buildSavedQueryFromRequest($request);
$search_engine->saveQuery($saved);
$filter_form = id(new AphrontFormView())
@@ -188,6 +189,46 @@
->appendChild($content);
}
+ // If the user wants to turn a particular column into a query, build an
+ // apropriate filter and redirect them to the query results page.
+ $query_column_id = $request->getInt('queryColumnID');
+ if ($query_column_id) {
+ $column_id_map = mpull($columns, null, 'getID');
+ $query_column = idx($column_id_map, $query_column_id);
+ if (!$query_column) {
+ return new Aphront404Response();
+ }
+
+ // Create a saved query to combine the active filter on the workboard
+ // with the column filter. If the user currently has constraints on the
+ // board, we want to add a new column or project constraint, not
+ // completely replace the constraints.
+ $saved_query = clone $saved;
+
+ if ($query_column->getProxyPHID()) {
+ $project_phids = $saved_query->getParameter('projectPHIDs');
+ if (!$project_phids) {
+ $project_phids = array();
+ }
+ $project_phids[] = $query_column->getProxyPHID();
+ $saved_query->setParameter('projectPHIDs', $project_phids);
+ } else {
+ $saved_query->setParameter(
+ 'columnPHIDs',
+ array($query_column->getPHID()));
+ }
+
+ $search_engine = id(new ManiphestTaskSearchEngine())
+ ->setViewer($viewer);
+ $search_engine->saveQuery($saved_query);
+
+ $query_key = $saved_query->getQueryKey();
+ $query_uri = new PhutilURI("/maniphest/query/{$query_key}/#R");
+
+ return id(new AphrontRedirectResponse())
+ ->setURI($query_uri);
+ }
+
$task_can_edit_map = id(new PhabricatorPolicyFilter())
->setViewer($viewer)
->requireCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT))
@@ -1069,8 +1110,14 @@
->setHref($batch_move_uri)
->setWorkflow(true);
- // Column Related Actions Below
- //
+ $query_uri = $request->getRequestURI();
+ $query_uri->setQueryParam('queryColumnID', $column->getID());
+
+ $column_items[] = id(new PhabricatorActionView())
+ ->setName(pht('View as Query'))
+ ->setIcon('fa-search')
+ ->setHref($query_uri);
+
$edit_uri = 'board/'.$this->id.'/edit/'.$column->getID().'/';
$column_items[] = id(new PhabricatorActionView())
->setName(pht('Edit Column'))

File Metadata

Mime Type
text/plain
Expires
Thu, May 9, 8:08 PM (3 w, 3 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6276415
Default Alt Text
D19366.diff (7 KB)

Event Timeline