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:
parent
e5e5974d9f
commit
6fa9b10914
11 changed files with 128 additions and 67 deletions
|
@ -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',
|
||||
|
|
|
@ -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';
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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(),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue