1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-10 00:42:41 +01:00

Collapse "Show unassigned tasks" in Maniphest into a parameterized owners typeahead

Summary: Ref T4100. Support viewer(), members(), and add a new none().

Test Plan:
  - Used all new functions.
  - Batch edited tasks with unassign action.
  - Saved a query from master, upgrade it to this patch, checkbox migrated cleanly into a "no one" token.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T4100

Differential Revision: https://secure.phabricator.com/D12470
This commit is contained in:
epriestley 2015-04-19 08:23:56 -07:00
parent e5e5974d9f
commit 6fa9b10914
11 changed files with 128 additions and 67 deletions

View file

@ -998,6 +998,7 @@ phutil_register_library_map(array(
'MacroCreateMemeConduitAPIMethod' => 'applications/macro/conduit/MacroCreateMemeConduitAPIMethod.php',
'MacroQueryConduitAPIMethod' => 'applications/macro/conduit/MacroQueryConduitAPIMethod.php',
'ManiphestAssignEmailCommand' => 'applications/maniphest/command/ManiphestAssignEmailCommand.php',
'ManiphestAssigneeDatasource' => 'applications/maniphest/typeahead/ManiphestAssigneeDatasource.php',
'ManiphestBatchEditController' => 'applications/maniphest/controller/ManiphestBatchEditController.php',
'ManiphestBulkEditCapability' => 'applications/maniphest/capability/ManiphestBulkEditCapability.php',
'ManiphestClaimEmailCommand' => 'applications/maniphest/command/ManiphestClaimEmailCommand.php',
@ -1031,6 +1032,8 @@ phutil_register_library_map(array(
'ManiphestInfoConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestInfoConduitAPIMethod.php',
'ManiphestNameIndex' => 'applications/maniphest/storage/ManiphestNameIndex.php',
'ManiphestNameIndexEventListener' => 'applications/maniphest/event/ManiphestNameIndexEventListener.php',
'ManiphestNoOwnerDatasource' => 'applications/maniphest/typeahead/ManiphestNoOwnerDatasource.php',
'ManiphestOwnerDatasource' => 'applications/maniphest/typeahead/ManiphestOwnerDatasource.php',
'ManiphestPriorityEmailCommand' => 'applications/maniphest/command/ManiphestPriorityEmailCommand.php',
'ManiphestQueryConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestQueryConduitAPIMethod.php',
'ManiphestQueryStatusesConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestQueryStatusesConduitAPIMethod.php',
@ -2639,8 +2642,6 @@ phutil_register_library_map(array(
'PhabricatorTypeaheadInvalidTokenException' => 'applications/typeahead/exception/PhabricatorTypeaheadInvalidTokenException.php',
'PhabricatorTypeaheadModularDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php',
'PhabricatorTypeaheadMonogramDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadMonogramDatasource.php',
'PhabricatorTypeaheadNoOwnerDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadNoOwnerDatasource.php',
'PhabricatorTypeaheadOwnerDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadOwnerDatasource.php',
'PhabricatorTypeaheadResult' => 'applications/typeahead/storage/PhabricatorTypeaheadResult.php',
'PhabricatorTypeaheadRuntimeCompositeDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadRuntimeCompositeDatasource.php',
'PhabricatorTypeaheadTokenView' => 'applications/typeahead/view/PhabricatorTypeaheadTokenView.php',
@ -4270,6 +4271,7 @@ phutil_register_library_map(array(
'MacroCreateMemeConduitAPIMethod' => 'MacroConduitAPIMethod',
'MacroQueryConduitAPIMethod' => 'MacroConduitAPIMethod',
'ManiphestAssignEmailCommand' => 'ManiphestEmailCommand',
'ManiphestAssigneeDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'ManiphestBatchEditController' => 'ManiphestController',
'ManiphestBulkEditCapability' => 'PhabricatorPolicyCapability',
'ManiphestClaimEmailCommand' => 'ManiphestEmailCommand',
@ -4304,6 +4306,8 @@ phutil_register_library_map(array(
'ManiphestInfoConduitAPIMethod' => 'ManiphestConduitAPIMethod',
'ManiphestNameIndex' => 'ManiphestDAO',
'ManiphestNameIndexEventListener' => 'PhabricatorEventListener',
'ManiphestNoOwnerDatasource' => 'PhabricatorTypeaheadDatasource',
'ManiphestOwnerDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'ManiphestPriorityEmailCommand' => 'ManiphestEmailCommand',
'ManiphestQueryConduitAPIMethod' => 'ManiphestConduitAPIMethod',
'ManiphestQueryStatusesConduitAPIMethod' => 'ManiphestConduitAPIMethod',
@ -6053,8 +6057,6 @@ phutil_register_library_map(array(
'PhabricatorTypeaheadInvalidTokenException' => 'Exception',
'PhabricatorTypeaheadModularDatasourceController' => 'PhabricatorTypeaheadDatasourceController',
'PhabricatorTypeaheadMonogramDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorTypeaheadNoOwnerDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorTypeaheadOwnerDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'PhabricatorTypeaheadRuntimeCompositeDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'PhabricatorTypeaheadTokenView' => 'AphrontTagView',
'PhabricatorTypeaheadUserParameterizedDatasource' => 'PhabricatorTypeaheadCompositeDatasource',

View file

@ -2,7 +2,6 @@
final class ManiphestTaskOwner extends ManiphestConstants {
const OWNER_UP_FOR_GRABS = 'PHID-!!!!-UP-FOR-GRABS';
const PROJECT_NO_PROJECT = 'PHID-!!!!-NO-PROJECT';
}

View file

@ -86,7 +86,7 @@ final class ManiphestBatchEditController extends ManiphestController {
$projects_source = new PhabricatorProjectDatasource();
$mailable_source = new PhabricatorMetaMTAMailableDatasource();
$mailable_source->setViewer($viewer);
$owner_source = new PhabricatorTypeaheadOwnerDatasource();
$owner_source = new ManiphestAssigneeDatasource();
$owner_source->setViewer($viewer);
require_celerity_resource('maniphest-batch-editor');
@ -265,7 +265,8 @@ final class ManiphestBatchEditController extends ManiphestController {
continue 2;
}
$value = head($value);
if ($value === ManiphestTaskOwner::OWNER_UP_FOR_GRABS) {
$no_owner = ManiphestNoOwnerDatasource::FUNCTION_TOKEN;
if ($value === ManiphestNoOwnerDatasource::FUNCTION_TOKEN) {
$value = null;
}
break;

View file

@ -73,9 +73,11 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
}
public function withOwners(array $owners) {
$no_owner = ManiphestNoOwnerDatasource::FUNCTION_TOKEN;
$this->includeUnowned = false;
foreach ($owners as $k => $phid) {
if ($phid == ManiphestTaskOwner::OWNER_UP_FOR_GRABS || $phid === null) {
if ($phid === $no_owner || $phid === null) {
$this->includeUnowned = true;
unset($owners[$k]);
break;

View file

@ -49,8 +49,6 @@ final class ManiphestTaskSearchEngine
'assignedPHIDs',
$this->readUsersFromRequest($request, 'assigned'));
$saved->setParameter('withUnassigned', $request->getBool('withUnassigned'));
$saved->setParameter(
'authorPHIDs',
$this->readUsersFromRequest($request, 'authors'));
@ -139,14 +137,13 @@ final class ManiphestTaskSearchEngine
$query->withSubscribers($subscriber_phids);
}
$with_unassigned = $saved->getParameter('withUnassigned');
if ($with_unassigned) {
$query->withOwners(array(null));
} else {
$assigned_phids = $saved->getParameter('assignedPHIDs', array());
if ($assigned_phids) {
$query->withOwners($assigned_phids);
}
$datasource = id(new ManiphestOwnerDatasource())
->setViewer($this->requireViewer());
$assigned_phids = $this->readAssignedPHIDs($saved);
$assigned_phids = $datasource->evaluateTokens($assigned_phids);
if ($assigned_phids) {
$query->withOwners($assigned_phids);
}
$statuses = $saved->getParameter('statuses');
@ -242,7 +239,8 @@ final class ManiphestTaskSearchEngine
AphrontFormView $form,
PhabricatorSavedQuery $saved) {
$assigned_phids = $saved->getParameter('assignedPHIDs', array());
$assigned_phids = $this->readAssignedPHIDs($saved);
$author_phids = $saved->getParameter('authorPHIDs', array());
$all_project_phids = $saved->getParameter(
'allProjectPHIDs',
@ -258,7 +256,6 @@ final class ManiphestTaskSearchEngine
array());
$subscriber_phids = $saved->getParameter('subscriberPHIDs', array());
$with_unassigned = $saved->getParameter('withUnassigned');
$with_no_projects = $saved->getParameter('withNoProject');
$statuses = $saved->getParameter('statuses', array());
@ -314,17 +311,10 @@ final class ManiphestTaskSearchEngine
$form
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new PhabricatorPeopleDatasource())
->setDatasource(new ManiphestOwnerDatasource())
->setName('assigned')
->setLabel(pht('Assigned To'))
->setValue($assigned_phids))
->appendChild(
id(new AphrontFormCheckboxControl())
->addCheckbox(
'withUnassigned',
1,
pht('Show only unassigned tasks.'),
$with_unassigned))
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new PhabricatorProjectDatasource())
@ -563,4 +553,17 @@ final class ManiphestTaskSearchEngine
->setShowBatchControls($this->showBatchControls);
}
private function readAssignedPHIDs(PhabricatorSavedQuery $saved) {
$assigned_phids = $saved->getParameter('assignedPHIDs', array());
// This may be present in old saved queries from before parameterized
// typeaheads, and is retained for compatibility. We could remove it by
// migrating old saved queries.
if ($saved->getParameter('withUnassigned')) {
$assigned_phids[] = ManiphestNoOwnerDatasource::FUNCTION_TOKEN;
}
return $assigned_phids;
}
}

View file

@ -1,20 +1,20 @@
<?php
final class PhabricatorTypeaheadOwnerDatasource
final class ManiphestAssigneeDatasource
extends PhabricatorTypeaheadCompositeDatasource {
public function getBrowseTitle() {
return pht('Browse Owners');
return pht('Browse Assignees');
}
public function getPlaceholderText() {
return pht('Type a user name or "none"...');
return pht('Type a username or "none"...');
}
public function getComponentDatasources() {
return array(
new PhabricatorPeopleDatasource(),
new PhabricatorTypeaheadNoOwnerDatasource(),
new ManiphestNoOwnerDatasource(),
);
}

View file

@ -0,0 +1,64 @@
<?php
final class ManiphestNoOwnerDatasource
extends PhabricatorTypeaheadDatasource {
const FUNCTION_TOKEN = 'none()';
public function getBrowseTitle() {
return pht('Browse No Owner');
}
public function getPlaceholderText() {
return pht('Type "none"...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorManiphestApplication';
}
public function getDatasourceFunctions() {
return array(
'none' => array(
'name' => pht('Find results which are not assigned.'),
),
);
}
public function loadResults() {
$results = array(
$this->buildNoOwnerResult(),
);
return $this->filterResultsAgainstTokens($results);
}
protected function evaluateFunction($function, array $argv_list) {
$results = array();
foreach ($argv_list as $argv) {
$results[] = self::FUNCTION_TOKEN;
}
return $results;
}
public function renderFunctionTokens($function, array $argv_list) {
$results = array();
foreach ($argv_list as $argv) {
$results[] = PhabricatorTypeaheadTokenView::newFromTypeaheadResult(
$this->buildNoOwnerResult());
}
return $results;
}
private function buildNoOwnerResult() {
$name = pht('No Owner');
return $this->newFunctionResult()
->setName($name.' none')
->setDisplayName($name)
->setIcon('fa-ban')
->setPHID('none()')
->setUnique(true);
}
}

View file

@ -0,0 +1,23 @@
<?php
final class ManiphestOwnerDatasource
extends PhabricatorTypeaheadCompositeDatasource {
public function getBrowseTitle() {
return pht('Browse Owners');
}
public function getPlaceholderText() {
return pht('Type a username or function...');
}
public function getComponentDatasources() {
return array(
new PhabricatorViewerDatasource(),
new ManiphestNoOwnerDatasource(),
new PhabricatorPeopleDatasource(),
new PhabricatorProjectMembersDatasource(),
);
}
}

View file

@ -126,7 +126,7 @@ final class PhabricatorSearchApplicationSearchEngine
id(new AphrontFormTokenizerControl())
->setName('ownerPHIDs')
->setLabel('Owners')
->setDatasource(new PhabricatorTypeaheadOwnerDatasource())
->setDatasource(new ManiphestOwnerDatasource())
->setValue($owner_phids))
->appendChild(
id(new AphrontFormCheckboxControl())

View file

@ -247,8 +247,7 @@ final class PhabricatorTypeaheadModularDatasourceController
// format to make it easier to debug typeahead output.
foreach ($sources as $key => $source) {
// This can happen with composite sources like user or project, as well
// generic ones like NoOwner
// This can happen with composite or generic sources.
if (!$source->getDatasourceApplicationClass()) {
continue;
}

View file

@ -1,32 +0,0 @@
<?php
final class PhabricatorTypeaheadNoOwnerDatasource
extends PhabricatorTypeaheadDatasource {
public function getBrowseTitle() {
return pht('Browse No Owner');
}
public function getPlaceholderText() {
return pht('Type "none"...');
}
public function getDatasourceApplicationClass() {
return null;
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$results = array();
$results[] = id(new PhabricatorTypeaheadResult())
->setName(pht('None'))
->setIcon('fa-ban orange')
->setPHID(ManiphestTaskOwner::OWNER_UP_FOR_GRABS);
return $results;
}
}