3 final class DifferentialRevisionSearchEngine
4 extends PhabricatorApplicationSearchEngine
{
6 public function getResultTypeDescription() {
7 return pht('Differential Revisions');
10 public function getApplicationClassName() {
11 return 'PhabricatorDifferentialApplication';
14 protected function newResultBuckets() {
15 return DifferentialRevisionResultBucket
::getAllResultBuckets();
18 public function newQuery() {
19 return id(new DifferentialRevisionQuery())
22 ->needReviewers(true);
25 protected function buildQueryFromParameters(array $map) {
26 $query = $this->newQuery();
28 if ($map['responsiblePHIDs']) {
29 $query->withResponsibleUsers($map['responsiblePHIDs']);
32 if ($map['authorPHIDs']) {
33 $query->withAuthors($map['authorPHIDs']);
36 if ($map['reviewerPHIDs']) {
37 $query->withReviewers($map['reviewerPHIDs']);
40 if ($map['repositoryPHIDs']) {
41 $query->withRepositoryPHIDs($map['repositoryPHIDs']);
44 if ($map['statuses']) {
45 $query->withStatuses($map['statuses']);
48 if ($map['createdStart'] ||
$map['createdEnd']) {
49 $query->withCreatedEpochBetween(
54 if ($map['modifiedStart'] ||
$map['modifiedEnd']) {
55 $query->withUpdatedEpochBetween(
56 $map['modifiedStart'],
60 if ($map['affectedPaths']) {
61 $query->withPaths($map['affectedPaths']);
67 protected function buildCustomSearchFields() {
69 id(new PhabricatorSearchDatasourceField())
70 ->setLabel(pht('Responsible Users'))
71 ->setKey('responsiblePHIDs')
72 ->setAliases(array('responsiblePHID', 'responsibles', 'responsible'))
73 ->setDatasource(new DifferentialResponsibleDatasource())
75 pht('Find revisions that a given user is responsible for.')),
76 id(new PhabricatorUsersSearchField())
77 ->setLabel(pht('Authors'))
78 ->setKey('authorPHIDs')
79 ->setAliases(array('author', 'authors', 'authorPHID'))
81 pht('Find revisions with specific authors.')),
82 id(new PhabricatorSearchDatasourceField())
83 ->setLabel(pht('Reviewers'))
84 ->setKey('reviewerPHIDs')
85 ->setAliases(array('reviewer', 'reviewers', 'reviewerPHID'))
86 ->setDatasource(new DifferentialReviewerFunctionDatasource())
88 pht('Find revisions with specific reviewers.')),
89 id(new PhabricatorSearchDatasourceField())
90 ->setLabel(pht('Repositories'))
91 ->setKey('repositoryPHIDs')
92 ->setAliases(array('repository', 'repositories', 'repositoryPHID'))
93 ->setDatasource(new DiffusionRepositoryFunctionDatasource())
95 pht('Find revisions from specific repositories.')),
96 id(new PhabricatorSearchDatasourceField())
97 ->setLabel(pht('Statuses'))
99 ->setAliases(array('status'))
100 ->setDatasource(new DifferentialRevisionStatusFunctionDatasource())
102 pht('Find revisions with particular statuses.')),
103 id(new PhabricatorSearchDateField())
104 ->setLabel(pht('Created After'))
105 ->setKey('createdStart')
107 pht('Find revisions created at or after a particular time.')),
108 id(new PhabricatorSearchDateField())
109 ->setLabel(pht('Created Before'))
110 ->setKey('createdEnd')
112 pht('Find revisions created at or before a particular time.')),
113 id(new PhabricatorSearchDateField())
114 ->setLabel(pht('Modified After'))
115 ->setKey('modifiedStart')
118 pht('Find revisions modified at or after a particular time.')),
119 id(new PhabricatorSearchDateField())
120 ->setLabel(pht('Modified Before'))
121 ->setKey('modifiedEnd')
124 pht('Find revisions modified at or before a particular time.')),
125 id(new PhabricatorSearchStringListField())
126 ->setKey('affectedPaths')
127 ->setLabel(pht('Affected Paths'))
129 pht('Search for revisions affecting particular paths.'))
134 protected function getURI($path) {
135 return '/differential/'.$path;
138 protected function getBuiltinQueryNames() {
141 if ($this->requireViewer()->isLoggedIn()) {
142 $names['active'] = pht('Active Revisions');
143 $names['authored'] = pht('Authored');
146 $names['all'] = pht('All Revisions');
151 public function buildSavedQueryFromBuiltin($query_key) {
152 $query = $this->newSavedQuery();
153 $query->setQueryKey($query_key);
155 $viewer = $this->requireViewer();
157 switch ($query_key) {
159 $bucket_key = DifferentialRevisionRequiredActionResultBucket
::BUCKETKEY
;
162 ->setParameter('responsiblePHIDs', array($viewer->getPHID()))
163 ->setParameter('statuses', array('open()'))
164 ->setParameter('bucket', $bucket_key);
167 ->setParameter('authorPHIDs', array($viewer->getPHID()));
172 return parent
::buildSavedQueryFromBuiltin($query_key);
175 private function getStatusOptions() {
177 DifferentialLegacyQuery
::STATUS_ANY
=> pht('All'),
178 DifferentialLegacyQuery
::STATUS_OPEN
=> pht('Open'),
179 DifferentialLegacyQuery
::STATUS_ACCEPTED
=> pht('Accepted'),
180 DifferentialLegacyQuery
::STATUS_NEEDS_REVIEW
=> pht('Needs Review'),
181 DifferentialLegacyQuery
::STATUS_NEEDS_REVISION
=> pht('Needs Revision'),
182 DifferentialLegacyQuery
::STATUS_CLOSED
=> pht('Closed'),
183 DifferentialLegacyQuery
::STATUS_ABANDONED
=> pht('Abandoned'),
187 protected function renderResultList(
189 PhabricatorSavedQuery
$query,
191 assert_instances_of($revisions, 'DifferentialRevision');
193 $viewer = $this->requireViewer();
194 $template = id(new DifferentialRevisionListView())
196 ->setNoBox($this->isPanelContext());
198 $bucket = $this->getResultBucket($query);
200 $unlanded = $this->loadUnlandedDependencies($revisions);
204 $bucket->setViewer($viewer);
207 $groups = $bucket->newResultGroups($query, $revisions);
209 foreach ($groups as $group) {
210 // Don't show groups in Dashboard Panels
211 if ($group->getObjects() ||
!$this->isPanelContext()) {
212 $views[] = id(clone $template)
213 ->setHeader($group->getName())
214 ->setNoDataString($group->getNoDataString())
215 ->setRevisions($group->getObjects());
218 } catch (Exception
$ex) {
219 $this->addError($ex->getMessage());
222 $views[] = id(clone $template)
223 ->setRevisions($revisions);
227 $views[] = id(new DifferentialRevisionListView())
229 ->setNoDataString(pht('No revisions found.'));
232 foreach ($views as $view) {
233 $view->setUnlandedDependencies($unlanded);
236 if (count($views) == 1) {
237 // Reduce this to a PHUIObjectItemListView so we can get the free
238 // support from ApplicationSearch.
239 $list = head($views)->render();
244 $result = new PhabricatorApplicationSearchResultView();
245 $result->setContent($list);
250 protected function getNewUserBody() {
251 $create_button = id(new PHUIButtonView())
253 ->setText(pht('Create a Diff'))
254 ->setHref('/differential/diff/create/')
255 ->setColor(PHUIButtonView
::GREEN
);
257 $icon = $this->getApplication()->getIcon();
258 $app_name = $this->getApplication()->getName();
259 $view = id(new PHUIBigInfoView())
261 ->setTitle(pht('Welcome to %s', $app_name))
263 pht('Pre-commit code review. Revisions that are waiting on your input '.
264 'will appear here.'))
265 ->addAction($create_button);
270 private function loadUnlandedDependencies(array $revisions) {
272 foreach ($revisions as $revision) {
273 if (!$revision->isAccepted()) {
277 $phids[] = $revision->getPHID();
284 $query = id(new PhabricatorEdgeQuery())
285 ->withSourcePHIDs($phids)
288 DifferentialRevisionDependsOnRevisionEdgeType
::EDGECONST
,
293 $revision_phids = $query->getDestinationPHIDs();
294 if (!$revision_phids) {
298 $viewer = $this->requireViewer();
300 $blocking_revisions = id(new DifferentialRevisionQuery())
302 ->withPHIDs($revision_phids)
305 $blocking_revisions = mpull($blocking_revisions, null, 'getPHID');
308 foreach ($revisions as $revision) {
309 $revision_phid = $revision->getPHID();
310 $blocking_phids = $query->getDestinationPHIDs(array($revision_phid));
311 $blocking = array_select_keys($blocking_revisions, $blocking_phids);
313 $result[$revision_phid] = $blocking;
320 protected function newExportFields() {
322 id(new PhabricatorStringExportField())
324 ->setLabel(pht('Monogram')),
325 id(new PhabricatorPHIDExportField())
326 ->setKey('authorPHID')
327 ->setLabel(pht('Author PHID')),
328 id(new PhabricatorStringExportField())
330 ->setLabel(pht('Author')),
331 id(new PhabricatorStringExportField())
333 ->setLabel(pht('Status')),
334 id(new PhabricatorStringExportField())
335 ->setKey('statusName')
336 ->setLabel(pht('Status Name')),
337 id(new PhabricatorURIExportField())
339 ->setLabel(pht('URI')),
340 id(new PhabricatorStringExportField())
342 ->setLabel(pht('Title')),
343 id(new PhabricatorStringExportField())
345 ->setLabel(pht('Summary')),
346 id(new PhabricatorStringExportField())
348 ->setLabel(pht('Test Plan')),
354 protected function newExportData(array $revisions) {
355 $viewer = $this->requireViewer();
358 foreach ($revisions as $revision) {
359 $phids[] = $revision->getAuthorPHID();
361 $handles = $viewer->loadHandles($phids);
364 foreach ($revisions as $revision) {
366 $author_phid = $revision->getAuthorPHID();
368 $author_name = $handles[$author_phid]->getName();
373 $status = $revision->getStatusObject();
374 $status_name = $status->getDisplayName();
375 $status_value = $status->getKey();
378 'monogram' => $revision->getMonogram(),
379 'authorPHID' => $author_phid,
380 'author' => $author_name,
381 'status' => $status_value,
382 'statusName' => $status_name,
383 'uri' => PhabricatorEnv
::getProductionURI($revision->getURI()),
384 'title' => (string)$revision->getTitle(),
385 'summary' => (string)$revision->getSummary(),
386 'testPlan' => (string)$revision->getTestPlan(),