Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/maniphest/query/ManiphestTaskSearchEngine.php
12256 views
1
<?php
2
3
final class ManiphestTaskSearchEngine
4
extends PhabricatorApplicationSearchEngine {
5
6
private $showBatchControls;
7
private $baseURI;
8
private $isBoardView;
9
10
public function setIsBoardView($is_board_view) {
11
$this->isBoardView = $is_board_view;
12
return $this;
13
}
14
15
public function getIsBoardView() {
16
return $this->isBoardView;
17
}
18
19
public function setBaseURI($base_uri) {
20
$this->baseURI = $base_uri;
21
return $this;
22
}
23
24
public function getBaseURI() {
25
return $this->baseURI;
26
}
27
28
public function setShowBatchControls($show_batch_controls) {
29
$this->showBatchControls = $show_batch_controls;
30
return $this;
31
}
32
33
public function getResultTypeDescription() {
34
return pht('Maniphest Tasks');
35
}
36
37
public function getApplicationClassName() {
38
return 'PhabricatorManiphestApplication';
39
}
40
41
public function newQuery() {
42
return id(new ManiphestTaskQuery())
43
->needProjectPHIDs(true);
44
}
45
46
protected function buildCustomSearchFields() {
47
// Hide the "Subtypes" constraint from the web UI if the install only
48
// defines one task subtype, since it isn't of any use in this case.
49
$subtype_map = id(new ManiphestTask())->newEditEngineSubtypeMap();
50
$hide_subtypes = ($subtype_map->getCount() == 1);
51
52
return array(
53
id(new PhabricatorOwnersSearchField())
54
->setLabel(pht('Assigned To'))
55
->setKey('assignedPHIDs')
56
->setConduitKey('assigned')
57
->setAliases(array('assigned'))
58
->setDescription(
59
pht('Search for tasks owned by a user from a list.')),
60
id(new PhabricatorUsersSearchField())
61
->setLabel(pht('Authors'))
62
->setKey('authorPHIDs')
63
->setAliases(array('author', 'authors'))
64
->setDescription(
65
pht('Search for tasks with given authors.')),
66
id(new PhabricatorSearchDatasourceField())
67
->setLabel(pht('Statuses'))
68
->setKey('statuses')
69
->setAliases(array('status'))
70
->setDescription(
71
pht('Search for tasks with given statuses.'))
72
->setDatasource(new ManiphestTaskStatusFunctionDatasource()),
73
id(new PhabricatorSearchDatasourceField())
74
->setLabel(pht('Priorities'))
75
->setKey('priorities')
76
->setAliases(array('priority'))
77
->setDescription(
78
pht('Search for tasks with given priorities.'))
79
->setConduitParameterType(new ConduitIntListParameterType())
80
->setDatasource(new ManiphestTaskPriorityDatasource()),
81
id(new PhabricatorSearchDatasourceField())
82
->setLabel(pht('Subtypes'))
83
->setKey('subtypes')
84
->setAliases(array('subtype'))
85
->setDescription(
86
pht('Search for tasks with given subtypes.'))
87
->setDatasource(new ManiphestTaskSubtypeDatasource())
88
->setIsHidden($hide_subtypes),
89
id(new PhabricatorPHIDsSearchField())
90
->setLabel(pht('Columns'))
91
->setKey('columnPHIDs')
92
->setAliases(array('column', 'columnPHID', 'columns')),
93
id(new PhabricatorSearchThreeStateField())
94
->setLabel(pht('Open Parents'))
95
->setKey('hasParents')
96
->setAliases(array('blocking'))
97
->setOptions(
98
pht('(Show All)'),
99
pht('Show Only Tasks With Open Parents'),
100
pht('Show Only Tasks Without Open Parents')),
101
id(new PhabricatorSearchThreeStateField())
102
->setLabel(pht('Open Subtasks'))
103
->setKey('hasSubtasks')
104
->setAliases(array('blocked'))
105
->setOptions(
106
pht('(Show All)'),
107
pht('Show Only Tasks With Open Subtasks'),
108
pht('Show Only Tasks Without Open Subtasks')),
109
id(new PhabricatorIDsSearchField())
110
->setLabel(pht('Parent IDs'))
111
->setKey('parentIDs')
112
->setAliases(array('parentID')),
113
id(new PhabricatorIDsSearchField())
114
->setLabel(pht('Subtask IDs'))
115
->setKey('subtaskIDs')
116
->setAliases(array('subtaskID')),
117
id(new PhabricatorSearchSelectField())
118
->setLabel(pht('Group By'))
119
->setKey('group')
120
->setOptions($this->getGroupOptions()),
121
id(new PhabricatorSearchDateField())
122
->setLabel(pht('Created After'))
123
->setKey('createdStart'),
124
id(new PhabricatorSearchDateField())
125
->setLabel(pht('Created Before'))
126
->setKey('createdEnd'),
127
id(new PhabricatorSearchDateField())
128
->setLabel(pht('Updated After'))
129
->setKey('modifiedStart'),
130
id(new PhabricatorSearchDateField())
131
->setLabel(pht('Updated Before'))
132
->setKey('modifiedEnd'),
133
id(new PhabricatorSearchDateField())
134
->setLabel(pht('Closed After'))
135
->setKey('closedStart'),
136
id(new PhabricatorSearchDateField())
137
->setLabel(pht('Closed Before'))
138
->setKey('closedEnd'),
139
id(new PhabricatorUsersSearchField())
140
->setLabel(pht('Closed By'))
141
->setKey('closerPHIDs')
142
->setAliases(array('closer', 'closerPHID', 'closers'))
143
->setDescription(pht('Search for tasks closed by certain users.')),
144
id(new PhabricatorSearchTextField())
145
->setLabel(pht('Page Size'))
146
->setKey('limit'),
147
);
148
}
149
150
protected function getDefaultFieldOrder() {
151
return array(
152
'assignedPHIDs',
153
'projectPHIDs',
154
'authorPHIDs',
155
'subscriberPHIDs',
156
'statuses',
157
'priorities',
158
'subtypes',
159
'hasParents',
160
'hasSubtasks',
161
'parentIDs',
162
'subtaskIDs',
163
'group',
164
'order',
165
'ids',
166
'...',
167
'createdStart',
168
'createdEnd',
169
'modifiedStart',
170
'modifiedEnd',
171
'closedStart',
172
'closedEnd',
173
'closerPHIDs',
174
'limit',
175
);
176
}
177
178
protected function getHiddenFields() {
179
$keys = array();
180
181
if ($this->getIsBoardView()) {
182
$keys[] = 'group';
183
$keys[] = 'order';
184
$keys[] = 'limit';
185
}
186
187
return $keys;
188
}
189
190
protected function buildQueryFromParameters(array $map) {
191
$query = $this->newQuery();
192
193
if ($map['assignedPHIDs']) {
194
$query->withOwners($map['assignedPHIDs']);
195
}
196
197
if ($map['authorPHIDs']) {
198
$query->withAuthors($map['authorPHIDs']);
199
}
200
201
if ($map['statuses']) {
202
$query->withStatuses($map['statuses']);
203
}
204
205
if ($map['priorities']) {
206
$query->withPriorities($map['priorities']);
207
}
208
209
if ($map['subtypes']) {
210
$query->withSubtypes($map['subtypes']);
211
}
212
213
if ($map['createdStart']) {
214
$query->withDateCreatedAfter($map['createdStart']);
215
}
216
217
if ($map['createdEnd']) {
218
$query->withDateCreatedBefore($map['createdEnd']);
219
}
220
221
if ($map['modifiedStart']) {
222
$query->withDateModifiedAfter($map['modifiedStart']);
223
}
224
225
if ($map['modifiedEnd']) {
226
$query->withDateModifiedBefore($map['modifiedEnd']);
227
}
228
229
if ($map['closedStart'] || $map['closedEnd']) {
230
$query->withClosedEpochBetween($map['closedStart'], $map['closedEnd']);
231
}
232
233
if ($map['closerPHIDs']) {
234
$query->withCloserPHIDs($map['closerPHIDs']);
235
}
236
237
if ($map['hasParents'] !== null) {
238
$query->withOpenParents($map['hasParents']);
239
}
240
241
if ($map['hasSubtasks'] !== null) {
242
$query->withOpenSubtasks($map['hasSubtasks']);
243
}
244
245
if ($map['parentIDs']) {
246
$query->withParentTaskIDs($map['parentIDs']);
247
}
248
249
if ($map['subtaskIDs']) {
250
$query->withSubtaskIDs($map['subtaskIDs']);
251
}
252
253
if ($map['columnPHIDs']) {
254
$query->withColumnPHIDs($map['columnPHIDs']);
255
}
256
257
$group = idx($map, 'group');
258
$group = idx($this->getGroupValues(), $group);
259
if ($group) {
260
$query->setGroupBy($group);
261
}
262
263
if ($map['ids']) {
264
$ids = $map['ids'];
265
foreach ($ids as $key => $id) {
266
$id = trim($id, ' Tt');
267
if (!$id || !is_numeric($id)) {
268
unset($ids[$key]);
269
} else {
270
$ids[$key] = $id;
271
}
272
}
273
274
if ($ids) {
275
$query->withIDs($ids);
276
}
277
}
278
279
return $query;
280
}
281
282
protected function getURI($path) {
283
if ($this->baseURI) {
284
return $this->baseURI.$path;
285
}
286
return '/maniphest/'.$path;
287
}
288
289
protected function getBuiltinQueryNames() {
290
$names = array();
291
292
if ($this->requireViewer()->isLoggedIn()) {
293
$names['assigned'] = pht('Assigned');
294
$names['authored'] = pht('Authored');
295
$names['subscribed'] = pht('Subscribed');
296
}
297
298
$names['open'] = pht('Open Tasks');
299
$names['all'] = pht('All Tasks');
300
301
return $names;
302
}
303
304
public function buildSavedQueryFromBuiltin($query_key) {
305
306
$query = $this->newSavedQuery();
307
$query->setQueryKey($query_key);
308
309
$viewer_phid = $this->requireViewer()->getPHID();
310
311
switch ($query_key) {
312
case 'all':
313
return $query;
314
case 'assigned':
315
return $query
316
->setParameter('assignedPHIDs', array($viewer_phid))
317
->setParameter(
318
'statuses',
319
ManiphestTaskStatus::getOpenStatusConstants());
320
case 'subscribed':
321
return $query
322
->setParameter('subscriberPHIDs', array($viewer_phid))
323
->setParameter(
324
'statuses',
325
ManiphestTaskStatus::getOpenStatusConstants());
326
case 'open':
327
return $query
328
->setParameter(
329
'statuses',
330
ManiphestTaskStatus::getOpenStatusConstants());
331
case 'authored':
332
return $query
333
->setParameter('authorPHIDs', array($viewer_phid))
334
->setParameter('order', 'created')
335
->setParameter('group', 'none');
336
}
337
338
return parent::buildSavedQueryFromBuiltin($query_key);
339
}
340
341
private function getGroupOptions() {
342
return array(
343
'priority' => pht('Priority'),
344
'assigned' => pht('Assigned'),
345
'status' => pht('Status'),
346
'project' => pht('Project'),
347
'none' => pht('None'),
348
);
349
}
350
351
private function getGroupValues() {
352
return array(
353
'priority' => ManiphestTaskQuery::GROUP_PRIORITY,
354
'assigned' => ManiphestTaskQuery::GROUP_OWNER,
355
'status' => ManiphestTaskQuery::GROUP_STATUS,
356
'project' => ManiphestTaskQuery::GROUP_PROJECT,
357
'none' => ManiphestTaskQuery::GROUP_NONE,
358
);
359
}
360
361
protected function renderResultList(
362
array $tasks,
363
PhabricatorSavedQuery $saved,
364
array $handles) {
365
366
$viewer = $this->requireViewer();
367
368
if ($this->isPanelContext()) {
369
$can_bulk_edit = false;
370
} else {
371
$can_bulk_edit = PhabricatorPolicyFilter::hasCapability(
372
$viewer,
373
$this->getApplication(),
374
ManiphestBulkEditCapability::CAPABILITY);
375
}
376
377
$list = id(new ManiphestTaskResultListView())
378
->setUser($viewer)
379
->setTasks($tasks)
380
->setSavedQuery($saved)
381
->setCanBatchEdit($can_bulk_edit)
382
->setShowBatchControls($this->showBatchControls);
383
384
$result = new PhabricatorApplicationSearchResultView();
385
$result->setContent($list);
386
387
return $result;
388
}
389
390
protected function willUseSavedQuery(PhabricatorSavedQuery $saved) {
391
392
// The 'withUnassigned' parameter may be present in old saved queries from
393
// before parameterized typeaheads, and is retained for compatibility. We
394
// could remove it by migrating old saved queries.
395
$assigned_phids = $saved->getParameter('assignedPHIDs', array());
396
if ($saved->getParameter('withUnassigned')) {
397
$assigned_phids[] = PhabricatorPeopleNoOwnerDatasource::FUNCTION_TOKEN;
398
}
399
$saved->setParameter('assignedPHIDs', $assigned_phids);
400
401
// The 'projects' and other parameters may be present in old saved queries
402
// from before parameterized typeaheads.
403
$project_phids = $saved->getParameter('projectPHIDs', array());
404
405
$old = $saved->getParameter('projects', array());
406
foreach ($old as $phid) {
407
$project_phids[] = $phid;
408
}
409
410
$all = $saved->getParameter('allProjectPHIDs', array());
411
foreach ($all as $phid) {
412
$project_phids[] = $phid;
413
}
414
415
$any = $saved->getParameter('anyProjectPHIDs', array());
416
foreach ($any as $phid) {
417
$project_phids[] = 'any('.$phid.')';
418
}
419
420
$not = $saved->getParameter('excludeProjectPHIDs', array());
421
foreach ($not as $phid) {
422
$project_phids[] = 'not('.$phid.')';
423
}
424
425
$users = $saved->getParameter('userProjectPHIDs', array());
426
foreach ($users as $phid) {
427
$project_phids[] = 'projects('.$phid.')';
428
}
429
430
$no = $saved->getParameter('withNoProject');
431
if ($no) {
432
$project_phids[] = 'null()';
433
}
434
435
$saved->setParameter('projectPHIDs', $project_phids);
436
}
437
438
protected function getNewUserBody() {
439
$viewer = $this->requireViewer();
440
441
$create_button = id(new ManiphestEditEngine())
442
->setViewer($viewer)
443
->newNUXBUtton(pht('Create a Task'));
444
445
$icon = $this->getApplication()->getIcon();
446
$app_name = $this->getApplication()->getName();
447
$view = id(new PHUIBigInfoView())
448
->setIcon($icon)
449
->setTitle(pht('Welcome to %s', $app_name))
450
->setDescription(
451
pht('Use Maniphest to track bugs, features, todos, or anything else '.
452
'you need to get done. Tasks assigned to you will appear here.'))
453
->addAction($create_button);
454
455
return $view;
456
}
457
458
459
protected function newExportFields() {
460
$fields = array(
461
id(new PhabricatorStringExportField())
462
->setKey('monogram')
463
->setLabel(pht('Monogram')),
464
id(new PhabricatorPHIDExportField())
465
->setKey('authorPHID')
466
->setLabel(pht('Author PHID')),
467
id(new PhabricatorStringExportField())
468
->setKey('author')
469
->setLabel(pht('Author')),
470
id(new PhabricatorPHIDExportField())
471
->setKey('ownerPHID')
472
->setLabel(pht('Owner PHID')),
473
id(new PhabricatorStringExportField())
474
->setKey('owner')
475
->setLabel(pht('Owner')),
476
id(new PhabricatorStringExportField())
477
->setKey('status')
478
->setLabel(pht('Status')),
479
id(new PhabricatorStringExportField())
480
->setKey('statusName')
481
->setLabel(pht('Status Name')),
482
id(new PhabricatorEpochExportField())
483
->setKey('dateClosed')
484
->setLabel(pht('Date Closed')),
485
id(new PhabricatorPHIDExportField())
486
->setKey('closerPHID')
487
->setLabel(pht('Closer PHID')),
488
id(new PhabricatorStringExportField())
489
->setKey('closer')
490
->setLabel(pht('Closer')),
491
id(new PhabricatorStringExportField())
492
->setKey('priority')
493
->setLabel(pht('Priority')),
494
id(new PhabricatorStringExportField())
495
->setKey('priorityName')
496
->setLabel(pht('Priority Name')),
497
id(new PhabricatorStringExportField())
498
->setKey('subtype')
499
->setLabel('Subtype'),
500
id(new PhabricatorURIExportField())
501
->setKey('uri')
502
->setLabel(pht('URI')),
503
id(new PhabricatorStringExportField())
504
->setKey('title')
505
->setLabel(pht('Title')),
506
id(new PhabricatorStringExportField())
507
->setKey('description')
508
->setLabel(pht('Description')),
509
);
510
511
if (ManiphestTaskPoints::getIsEnabled()) {
512
$fields[] = id(new PhabricatorDoubleExportField())
513
->setKey('points')
514
->setLabel('Points');
515
}
516
517
return $fields;
518
}
519
520
protected function newExportData(array $tasks) {
521
$viewer = $this->requireViewer();
522
523
$phids = array();
524
foreach ($tasks as $task) {
525
$phids[] = $task->getAuthorPHID();
526
$phids[] = $task->getOwnerPHID();
527
$phids[] = $task->getCloserPHID();
528
}
529
$handles = $viewer->loadHandles($phids);
530
531
$export = array();
532
foreach ($tasks as $task) {
533
534
$author_phid = $task->getAuthorPHID();
535
if ($author_phid) {
536
$author_name = $handles[$author_phid]->getName();
537
} else {
538
$author_name = null;
539
}
540
541
$owner_phid = $task->getOwnerPHID();
542
if ($owner_phid) {
543
$owner_name = $handles[$owner_phid]->getName();
544
} else {
545
$owner_name = null;
546
}
547
548
$closer_phid = $task->getCloserPHID();
549
if ($closer_phid) {
550
$closer_name = $handles[$closer_phid]->getName();
551
} else {
552
$closer_name = null;
553
}
554
555
$status_value = $task->getStatus();
556
$status_name = ManiphestTaskStatus::getTaskStatusName($status_value);
557
558
$priority_value = $task->getPriority();
559
$priority_name = ManiphestTaskPriority::getTaskPriorityName(
560
$priority_value);
561
562
$export[] = array(
563
'monogram' => $task->getMonogram(),
564
'authorPHID' => $author_phid,
565
'author' => $author_name,
566
'ownerPHID' => $owner_phid,
567
'owner' => $owner_name,
568
'status' => $status_value,
569
'statusName' => $status_name,
570
'priority' => $priority_value,
571
'priorityName' => $priority_name,
572
'points' => $task->getPoints(),
573
'subtype' => $task->getSubtype(),
574
'title' => $task->getTitle(),
575
'uri' => PhabricatorEnv::getProductionURI($task->getURI()),
576
'description' => $task->getDescription(),
577
'dateClosed' => $task->getClosedEpoch(),
578
'closerPHID' => $closer_phid,
579
'closer' => $closer_name,
580
);
581
}
582
583
return $export;
584
}
585
}
586
587