diff --git a/resources/sql/autopatches/20191113.identity.03.unassigned.sql b/resources/sql/autopatches/20191113.identity.03.unassigned.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20191113.identity.03.unassigned.sql @@ -0,0 +1,3 @@ +UPDATE {$NAMESPACE}_repository.repository_identity + SET currentEffectiveUserPHID = NULL + WHERE currentEffectiveUserPHID = 'unassigned()'; diff --git a/src/applications/diffusion/controller/DiffusionIdentityViewController.php b/src/applications/diffusion/controller/DiffusionIdentityViewController.php --- a/src/applications/diffusion/controller/DiffusionIdentityViewController.php +++ b/src/applications/diffusion/controller/DiffusionIdentityViewController.php @@ -25,6 +25,9 @@ ->setHeaderIcon('fa-globe'); $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb( + pht('Identities'), + $this->getApplicationURI('identity/')); $crumbs->addTextCrumb($identity->getObjectName()); $crumbs->setBorder(true); diff --git a/src/applications/diffusion/query/DiffusionRepositoryIdentitySearchEngine.php b/src/applications/diffusion/query/DiffusionRepositoryIdentitySearchEngine.php --- a/src/applications/diffusion/query/DiffusionRepositoryIdentitySearchEngine.php +++ b/src/applications/diffusion/query/DiffusionRepositoryIdentitySearchEngine.php @@ -17,21 +17,35 @@ protected function buildCustomSearchFields() { return array( + id(new PhabricatorUsersSearchField()) + ->setLabel(pht('Matching Users')) + ->setKey('effectivePHIDs') + ->setAliases( + array( + 'effective', + 'effectivePHID', + )) + ->setDescription(pht('Search for identities by effective user.')), id(new DiffusionIdentityAssigneeSearchField()) ->setLabel(pht('Assigned To')) - ->setKey('assignee') - ->setDescription(pht('Search for identities by assignee.')), + ->setKey('assignedPHIDs') + ->setAliases( + array( + 'assigned', + 'assignedPHID', + )) + ->setDescription(pht('Search for identities by explicit assignee.')), id(new PhabricatorSearchTextField()) ->setLabel(pht('Identity Contains')) ->setKey('match') ->setDescription(pht('Search for identities by substring.')), id(new PhabricatorSearchThreeStateField()) - ->setLabel(pht('Is Assigned')) + ->setLabel(pht('Has Matching User')) ->setKey('hasEffectivePHID') ->setOptions( pht('(Show All)'), - pht('Show Only Assigned Identities'), - pht('Show Only Unassigned Identities')), + pht('Show Identities With Matching Users'), + pht('Show Identities Without Matching Users')), ); } @@ -46,8 +60,12 @@ $query->withIdentityNameLike($map['match']); } - if ($map['assignee']) { - $query->withAssigneePHIDs($map['assignee']); + if ($map['assignedPHIDs']) { + $query->withAssignedPHIDs($map['assignedPHIDs']); + } + + if ($map['effectivePHIDs']) { + $query->withEffectivePHIDs($map['effectivePHIDs']); } return $query; @@ -86,15 +104,54 @@ $viewer = $this->requireViewer(); - $list = new PHUIObjectItemListView(); - $list->setUser($viewer); + $list = id(new PHUIObjectItemListView()) + ->setViewer($viewer); + + $phids = array(); + foreach ($identities as $identity) { + $phids[] = $identity->getCurrentEffectiveUserPHID(); + $phids[] = $identity->getManuallySetUserPHID(); + } + + $handles = $viewer->loadHandles($phids); + + $unassigned = DiffusionIdentityUnassignedDatasource::FUNCTION_TOKEN; + foreach ($identities as $identity) { $item = id(new PHUIObjectItemView()) - ->setObjectName(pht('Identity %d', $identity->getID())) + ->setObjectName($identity->getObjectName()) ->setHeader($identity->getIdentityShortName()) ->setHref($identity->getURI()) ->setObject($identity); + $status_icon = 'fa-circle-o grey'; + + $effective_phid = $identity->getCurrentEffectiveUserPHID(); + if ($effective_phid) { + $item->addIcon( + 'fa-id-badge', + pht('Matches User: %s', $handles[$effective_phid]->getName())); + + $status_icon = 'fa-id-badge'; + } + + $assigned_phid = $identity->getManuallySetUserPHID(); + if ($assigned_phid) { + if ($assigned_phid === $unassigned) { + $item->addIcon( + 'fa-ban', + pht('Explicitly Unassigned')); + $status_icon = 'fa-ban'; + } else { + $item->addIcon( + 'fa-user', + pht('Assigned To: %s', $handles[$assigned_phid]->getName())); + $status_icon = 'fa-user'; + } + } + + $item->setStatusIcon($status_icon); + $list->addItem($item); } diff --git a/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php b/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php --- a/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php +++ b/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php @@ -7,7 +7,8 @@ private $phids; private $identityNames; private $emailAddresses; - private $assigneePHIDs; + private $assignedPHIDs; + private $effectivePHIDs; private $identityNameLike; private $hasEffectivePHID; @@ -36,8 +37,13 @@ return $this; } - public function withAssigneePHIDs(array $assignees) { - $this->assigneePHIDs = $assignees; + public function withAssignedPHIDs(array $assigned) { + $this->assignedPHIDs = $assigned; + return $this; + } + + public function withEffectivePHIDs(array $effective) { + $this->effectivePHIDs = $effective; return $this; } @@ -75,11 +81,18 @@ $this->phids); } - if ($this->assigneePHIDs !== null) { + if ($this->assignedPHIDs !== null) { + $where[] = qsprintf( + $conn, + 'repository_identity.manuallySetUserPHID IN (%Ls)', + $this->assignedPHIDs); + } + + if ($this->effectivePHIDs !== null) { $where[] = qsprintf( $conn, 'repository_identity.currentEffectiveUserPHID IN (%Ls)', - $this->assigneePHIDs); + $this->effectivePHIDs); } if ($this->hasEffectivePHID !== null) { diff --git a/src/applications/repository/storage/PhabricatorRepositoryIdentity.php b/src/applications/repository/storage/PhabricatorRepositoryIdentity.php --- a/src/applications/repository/storage/PhabricatorRepositoryIdentity.php +++ b/src/applications/repository/storage/PhabricatorRepositoryIdentity.php @@ -96,11 +96,18 @@ public function save() { if ($this->manuallySetUserPHID) { - $this->currentEffectiveUserPHID = $this->manuallySetUserPHID; + $unassigned = DiffusionIdentityUnassignedDatasource::FUNCTION_TOKEN; + if ($this->manuallySetUserPHID === $unassigned) { + $effective_phid = null; + } else { + $effective_phid = $this->manuallySetUserPHID; + } } else { - $this->currentEffectiveUserPHID = $this->automaticGuessedUserPHID; + $effective_phid = $this->automaticGuessedUserPHID; } + $this->setCurrentEffectiveUserPHID($effective_phid); + $email_address = $this->getIdentityEmailAddress(); // Raw identities are unrestricted binary data, and may consequently