2011-02-08 19:53:59 +01:00
|
|
|
<?php
|
|
|
|
|
2012-03-10 00:46:25 +01:00
|
|
|
final class ManiphestTaskDetailController extends ManiphestController {
|
2011-02-08 19:53:59 +01:00
|
|
|
|
2013-09-25 22:44:52 +02:00
|
|
|
public function shouldAllowPublic() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-08-02 02:06:57 +02:00
|
|
|
public function handleRequest(AphrontRequest $request) {
|
|
|
|
$viewer = $this->getViewer();
|
|
|
|
$id = $request->getURIData('id');
|
2011-02-08 19:53:59 +01:00
|
|
|
|
2013-09-25 22:44:14 +02:00
|
|
|
$task = id(new ManiphestTaskQuery())
|
2015-08-02 02:06:57 +02:00
|
|
|
->setViewer($viewer)
|
|
|
|
->withIDs(array($id))
|
2014-12-11 01:27:30 +01:00
|
|
|
->needSubscriberPHIDs(true)
|
2013-09-25 22:44:14 +02:00
|
|
|
->executeOne();
|
2011-03-31 06:38:24 +02:00
|
|
|
if (!$task) {
|
|
|
|
return new Aphront404Response();
|
|
|
|
}
|
2011-02-08 19:53:59 +01:00
|
|
|
|
2013-09-17 00:58:35 +02:00
|
|
|
$field_list = PhabricatorCustomField::getObjectFields(
|
|
|
|
$task,
|
|
|
|
PhabricatorCustomField::ROLE_VIEW);
|
2014-02-21 23:44:01 +01:00
|
|
|
$field_list
|
2015-08-02 02:06:57 +02:00
|
|
|
->setViewer($viewer)
|
2014-02-21 23:44:01 +01:00
|
|
|
->readFieldsFromStorage($task);
|
2013-03-08 02:24:58 +01:00
|
|
|
|
2014-07-18 00:42:06 +02:00
|
|
|
$e_commit = ManiphestTaskHasCommitEdgeType::EDGECONST;
|
2014-12-28 15:10:49 +01:00
|
|
|
$e_dep_on = ManiphestTaskDependsOnTaskEdgeType::EDGECONST;
|
|
|
|
$e_dep_by = ManiphestTaskDependedOnByTaskEdgeType::EDGECONST;
|
2014-07-18 00:41:08 +02:00
|
|
|
$e_rev = ManiphestTaskHasRevisionEdgeType::EDGECONST;
|
2015-01-02 00:11:41 +01:00
|
|
|
$e_mock = ManiphestTaskHasMockEdgeType::EDGECONST;
|
2012-07-19 05:41:42 +02:00
|
|
|
|
|
|
|
$phid = $task->getPHID();
|
|
|
|
|
|
|
|
$query = id(new PhabricatorEdgeQuery())
|
|
|
|
->withSourcePHIDs(array($phid))
|
|
|
|
->withEdgeTypes(
|
|
|
|
array(
|
|
|
|
$e_commit,
|
|
|
|
$e_dep_on,
|
|
|
|
$e_dep_by,
|
2012-07-20 17:59:39 +02:00
|
|
|
$e_rev,
|
2013-07-20 00:59:29 +02:00
|
|
|
$e_mock,
|
2012-07-19 05:41:42 +02:00
|
|
|
));
|
2012-12-11 23:03:16 +01:00
|
|
|
$edges = idx($query->execute(), $phid);
|
2012-07-19 05:41:42 +02:00
|
|
|
$phids = array_fill_keys($query->getDestinationPHIDs(), true);
|
2012-04-05 02:34:25 +02:00
|
|
|
|
2011-02-08 19:53:59 +01:00
|
|
|
if ($task->getOwnerPHID()) {
|
|
|
|
$phids[$task->getOwnerPHID()] = true;
|
|
|
|
}
|
|
|
|
$phids[$task->getAuthorPHID()] = true;
|
|
|
|
|
2011-08-03 23:20:05 +02:00
|
|
|
$phids = array_keys($phids);
|
2015-08-02 02:06:57 +02:00
|
|
|
$handles = $viewer->loadHandles($phids);
|
2013-03-08 02:24:58 +01:00
|
|
|
|
2015-12-08 15:26:30 +01:00
|
|
|
$engine = id(new PhabricatorMarkupEngine())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->setContextObject($task)
|
|
|
|
->addObject($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION);
|
2012-07-11 20:40:10 +02:00
|
|
|
|
2014-11-13 23:44:55 +01:00
|
|
|
$timeline = $this->buildTransactionTimeline(
|
|
|
|
$task,
|
|
|
|
new ManiphestTransactionQuery(),
|
|
|
|
$engine);
|
2013-03-08 02:24:33 +01:00
|
|
|
|
2013-04-09 21:42:03 +02:00
|
|
|
$actions = $this->buildActionView($task);
|
2012-12-11 23:03:16 +01:00
|
|
|
|
2015-12-04 15:37:36 +01:00
|
|
|
$monogram = $task->getMonogram();
|
2013-12-19 02:47:34 +01:00
|
|
|
$crumbs = $this->buildApplicationCrumbs()
|
2015-12-04 15:37:36 +01:00
|
|
|
->addTextCrumb($monogram, '/'.$monogram);
|
2012-12-11 23:03:16 +01:00
|
|
|
|
|
|
|
$header = $this->buildHeaderView($task);
|
2013-10-11 16:53:56 +02:00
|
|
|
$properties = $this->buildPropertyView(
|
2015-03-30 03:56:28 +02:00
|
|
|
$task, $field_list, $edges, $actions, $handles);
|
2013-10-11 16:53:56 +02:00
|
|
|
$description = $this->buildDescriptionView($task, $engine);
|
2012-12-11 23:03:16 +01:00
|
|
|
|
2013-09-29 00:55:38 +02:00
|
|
|
$object_box = id(new PHUIObjectBoxView())
|
|
|
|
->setHeader($header)
|
2013-10-11 16:53:56 +02:00
|
|
|
->addPropertyList($properties);
|
|
|
|
|
|
|
|
if ($description) {
|
|
|
|
$object_box->addPropertyList($description);
|
|
|
|
}
|
2013-09-29 00:55:38 +02:00
|
|
|
|
2015-12-04 15:37:36 +01:00
|
|
|
$title = pht('%s %s', $monogram, $task->getTitle());
|
|
|
|
|
|
|
|
$comment_view = id(new ManiphestEditEngine())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->buildEditEngineCommentView($task);
|
2015-11-29 02:49:56 +01:00
|
|
|
|
2015-12-04 16:12:12 +01:00
|
|
|
$timeline->setQuoteRef($monogram);
|
|
|
|
$comment_view->setTransactionTimeline($timeline);
|
|
|
|
|
2015-11-29 02:49:56 +01:00
|
|
|
return $this->newPage()
|
|
|
|
->setTitle($title)
|
|
|
|
->setCrumbs($crumbs)
|
|
|
|
->setPageObjectPHIDs(
|
|
|
|
array(
|
|
|
|
$task->getPHID(),
|
|
|
|
))
|
|
|
|
->appendChild(
|
|
|
|
array(
|
|
|
|
$object_box,
|
|
|
|
$timeline,
|
2015-12-04 15:37:36 +01:00
|
|
|
$comment_view,
|
2015-11-29 02:49:56 +01:00
|
|
|
));
|
2011-02-08 19:53:59 +01:00
|
|
|
}
|
2011-02-19 07:15:28 +01:00
|
|
|
|
2012-12-11 23:03:16 +01:00
|
|
|
private function buildHeaderView(ManiphestTask $task) {
|
2013-09-17 18:12:37 +02:00
|
|
|
$view = id(new PHUIHeaderView())
|
2013-09-25 22:44:45 +02:00
|
|
|
->setHeader($task->getTitle())
|
|
|
|
->setUser($this->getRequest()->getUser())
|
|
|
|
->setPolicyObject($task);
|
2012-12-11 23:03:16 +01:00
|
|
|
|
2013-09-24 17:42:04 +02:00
|
|
|
$status = $task->getStatus();
|
|
|
|
$status_name = ManiphestTaskStatus::renderFullDescription($status);
|
|
|
|
|
|
|
|
$view->addProperty(PHUIHeaderView::PROPERTY_STATUS, $status_name);
|
2012-12-11 23:03:16 +01:00
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private function buildActionView(ManiphestTask $task) {
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$id = $task->getID();
|
|
|
|
$phid = $task->getPHID();
|
|
|
|
|
2013-09-25 22:44:52 +02:00
|
|
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
|
|
|
$viewer,
|
|
|
|
$task,
|
|
|
|
PhabricatorPolicyCapability::CAN_EDIT);
|
|
|
|
|
2013-07-12 20:39:47 +02:00
|
|
|
$view = id(new PhabricatorActionListView())
|
|
|
|
->setUser($viewer)
|
Remove all setObjectURI() from ActionListViews
Summary:
Ref T10004. After D14804, we get this behavior by default and no longer need to set it explicitly.
(If some endpoint did eventually need to set it explicitly, it could just change what it passes to `setHref()`, but I believe we currently have no such endpoints and do not foresee ever having any.)
Test Plan:
- As a logged out user, clicked various links in Differential, Maniphest, Files, etc., always got redirected to a sensible place after login.
- Grepped for `setObjectURI()`, `getObjectURI()` (there are a few remaining callsites, but to a different method with the same name in Doorkeeper).
Reviewers: chad
Reviewed By: chad
Subscribers: hach-que
Maniphest Tasks: T10004
Differential Revision: https://secure.phabricator.com/D14805
2015-12-17 15:31:33 +01:00
|
|
|
->setObject($task);
|
2013-09-25 22:44:52 +02:00
|
|
|
|
|
|
|
$view->addAction(
|
2012-12-11 23:03:16 +01:00
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setName(pht('Edit Task'))
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-pencil')
|
2015-12-09 01:54:46 +01:00
|
|
|
->setHref($this->getApplicationURI("/task/edit/{$id}/"))
|
2013-09-25 22:44:52 +02:00
|
|
|
->setDisabled(!$can_edit)
|
|
|
|
->setWorkflow(!$can_edit));
|
2012-12-11 23:03:16 +01:00
|
|
|
|
|
|
|
$view->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
2013-07-17 19:01:13 +02:00
|
|
|
->setName(pht('Merge Duplicates In'))
|
2012-12-11 23:03:16 +01:00
|
|
|
->setHref("/search/attach/{$phid}/TASK/merge/")
|
|
|
|
->setWorkflow(true)
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-compress')
|
2013-09-25 22:44:52 +02:00
|
|
|
->setDisabled(!$can_edit)
|
2013-10-16 19:35:52 +02:00
|
|
|
->setWorkflow(true));
|
2012-12-11 23:03:16 +01:00
|
|
|
|
2015-12-08 16:54:01 +01:00
|
|
|
$edit_config = id(new ManiphestEditEngine())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->loadDefaultEditConfiguration();
|
|
|
|
|
|
|
|
$can_create = (bool)$edit_config;
|
|
|
|
if ($can_create) {
|
|
|
|
$form_key = $edit_config->getIdentifier();
|
2015-12-14 23:51:22 +01:00
|
|
|
$edit_uri = id(new PhutilURI("/task/edit/form/{$form_key}/"))
|
|
|
|
->setQueryParam('parent', $id)
|
|
|
|
->setQueryParam('template', $id)
|
|
|
|
->setQueryParam('status', ManiphestTaskStatus::getDefaultStatus());
|
2015-12-08 16:54:01 +01:00
|
|
|
$edit_uri = $this->getApplicationURI($edit_uri);
|
|
|
|
} else {
|
|
|
|
// TODO: This will usually give us a somewhat-reasonable error page, but
|
|
|
|
// could be a bit cleaner.
|
2015-12-09 01:54:46 +01:00
|
|
|
$edit_uri = "/task/edit/{$id}/";
|
2015-12-08 16:54:01 +01:00
|
|
|
$edit_uri = $this->getApplicationURI($edit_uri);
|
|
|
|
}
|
|
|
|
|
2012-12-11 23:03:16 +01:00
|
|
|
$view->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setName(pht('Create Subtask'))
|
2015-12-08 16:54:01 +01:00
|
|
|
->setHref($edit_uri)
|
2015-10-18 23:43:29 +02:00
|
|
|
->setIcon('fa-level-down')
|
2015-10-18 13:22:05 +02:00
|
|
|
->setDisabled(!$can_create)
|
2015-10-18 23:43:29 +02:00
|
|
|
->setWorkflow(!$can_create));
|
2012-12-11 23:03:16 +01:00
|
|
|
|
|
|
|
$view->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
"Blocks" instead of "Dependent Tasks"
Summary: Fixes T5021, UI labels for the fields, "Edit Dependencies" in the action list, transaction strings ("added dependent tasks", etc), UI strings in the dependencies dialog (title/submit/etc)
Test Plan: Open task, edit blocks, dialog should have new term, task history should show "blocks" instead of "dependencies"
Reviewers: epriestley, #blessed_reviewers
Reviewed By: epriestley, #blessed_reviewers
Subscribers: epriestley, Korvin
Maniphest Tasks: T5021
Differential Revision: https://secure.phabricator.com/D9270
2014-05-23 22:50:20 +02:00
|
|
|
->setName(pht('Edit Blocking Tasks'))
|
|
|
|
->setHref("/search/attach/{$phid}/TASK/blocks/")
|
2012-12-11 23:03:16 +01:00
|
|
|
->setWorkflow(true)
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-link')
|
2013-09-25 22:44:52 +02:00
|
|
|
->setDisabled(!$can_edit)
|
2013-10-01 21:01:55 +02:00
|
|
|
->setWorkflow(true));
|
2012-12-11 23:03:16 +01:00
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildPropertyView(
|
|
|
|
ManiphestTask $task,
|
2013-09-17 01:02:27 +02:00
|
|
|
PhabricatorCustomFieldList $field_list,
|
2012-12-11 23:03:16 +01:00
|
|
|
array $edges,
|
2015-03-30 03:56:28 +02:00
|
|
|
PhabricatorActionListView $actions,
|
|
|
|
$handles) {
|
2012-12-11 23:03:16 +01:00
|
|
|
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
2013-10-11 16:53:56 +02:00
|
|
|
$view = id(new PHUIPropertyListView())
|
2013-02-15 16:47:14 +01:00
|
|
|
->setUser($viewer)
|
2013-10-11 16:53:56 +02:00
|
|
|
->setObject($task)
|
|
|
|
->setActionList($actions);
|
2012-12-11 23:03:16 +01:00
|
|
|
|
2015-12-24 19:14:10 +01:00
|
|
|
$owner_phid = $task->getOwnerPHID();
|
|
|
|
if ($owner_phid) {
|
|
|
|
$assigned_to = $handles
|
|
|
|
->renderHandle($owner_phid)
|
|
|
|
->setShowHovercard(true);
|
|
|
|
} else {
|
|
|
|
$assigned_to = phutil_tag('em', array(), pht('None'));
|
|
|
|
}
|
|
|
|
|
|
|
|
$view->addProperty(pht('Assigned To'), $assigned_to);
|
2012-12-11 23:03:16 +01:00
|
|
|
|
|
|
|
$view->addProperty(
|
|
|
|
pht('Priority'),
|
2013-01-29 20:01:47 +01:00
|
|
|
ManiphestTaskPriority::getTaskPriorityName($task->getPriority()));
|
2012-12-11 23:03:16 +01:00
|
|
|
|
2015-12-24 19:14:10 +01:00
|
|
|
$author = $handles
|
|
|
|
->renderHandle($task->getAuthorPHID())
|
|
|
|
->setShowHovercard(true);
|
|
|
|
|
|
|
|
$view->addProperty(pht('Author'), $author);
|
2012-12-11 23:03:16 +01:00
|
|
|
|
|
|
|
$source = $task->getOriginalEmailSource();
|
|
|
|
if ($source) {
|
|
|
|
$subject = '[T'.$task->getID().'] '.$task->getTitle();
|
|
|
|
$view->addProperty(
|
|
|
|
pht('From Email'),
|
2013-01-18 03:43:35 +01:00
|
|
|
phutil_tag(
|
2012-12-11 23:03:16 +01:00
|
|
|
'a',
|
|
|
|
array(
|
2014-10-07 15:01:04 +02:00
|
|
|
'href' => 'mailto:'.$source.'?subject='.$subject,
|
2013-07-20 00:59:29 +02:00
|
|
|
),
|
2013-01-18 03:43:35 +01:00
|
|
|
$source));
|
2012-12-11 23:03:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$edge_types = array(
|
2014-12-28 15:10:49 +01:00
|
|
|
ManiphestTaskDependedOnByTaskEdgeType::EDGECONST
|
2014-07-18 00:41:08 +02:00
|
|
|
=> pht('Blocks'),
|
2014-12-28 15:10:49 +01:00
|
|
|
ManiphestTaskDependsOnTaskEdgeType::EDGECONST
|
2014-07-18 00:41:08 +02:00
|
|
|
=> pht('Blocked By'),
|
|
|
|
ManiphestTaskHasRevisionEdgeType::EDGECONST
|
|
|
|
=> pht('Differential Revisions'),
|
2015-01-02 00:11:41 +01:00
|
|
|
ManiphestTaskHasMockEdgeType::EDGECONST
|
2014-07-18 00:41:08 +02:00
|
|
|
=> pht('Pholio Mocks'),
|
2012-12-11 23:03:16 +01:00
|
|
|
);
|
|
|
|
|
2013-04-06 20:40:43 +02:00
|
|
|
$revisions_commits = array();
|
|
|
|
|
|
|
|
$commit_phids = array_keys(
|
2014-07-18 00:42:06 +02:00
|
|
|
$edges[ManiphestTaskHasCommitEdgeType::EDGECONST]);
|
2013-04-06 20:40:43 +02:00
|
|
|
if ($commit_phids) {
|
2015-01-01 04:43:26 +01:00
|
|
|
$commit_drev = DiffusionCommitHasRevisionEdgeType::EDGECONST;
|
2013-04-13 07:48:16 +02:00
|
|
|
$drev_edges = id(new PhabricatorEdgeQuery())
|
|
|
|
->withSourcePHIDs($commit_phids)
|
|
|
|
->withEdgeTypes(array($commit_drev))
|
|
|
|
->execute();
|
2013-04-06 20:40:43 +02:00
|
|
|
|
2013-04-13 07:48:16 +02:00
|
|
|
foreach ($commit_phids as $phid) {
|
2015-12-24 21:33:13 +01:00
|
|
|
$revisions_commits[$phid] = $handles->renderHandle($phid)
|
|
|
|
->setShowHovercard(true);
|
2013-04-13 07:48:16 +02:00
|
|
|
$revision_phid = key($drev_edges[$phid][$commit_drev]);
|
2015-03-30 03:56:28 +02:00
|
|
|
$revision_handle = $handles->getHandleIfExists($revision_phid);
|
2013-04-06 20:40:43 +02:00
|
|
|
if ($revision_handle) {
|
2014-07-18 00:41:08 +02:00
|
|
|
$task_drev = ManiphestTaskHasRevisionEdgeType::EDGECONST;
|
2013-04-13 07:48:16 +02:00
|
|
|
unset($edges[$task_drev][$revision_phid]);
|
2013-04-06 20:40:43 +02:00
|
|
|
$revisions_commits[$phid] = hsprintf(
|
|
|
|
'%s / %s',
|
2015-12-24 21:33:13 +01:00
|
|
|
$revision_handle->renderHovercardLink($revision_handle->getName()),
|
2013-04-06 20:40:43 +02:00
|
|
|
$revisions_commits[$phid]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-11 23:03:16 +01:00
|
|
|
foreach ($edge_types as $edge_type => $edge_name) {
|
|
|
|
if ($edges[$edge_type]) {
|
2015-03-30 15:18:54 +02:00
|
|
|
$edge_handles = $viewer->loadHandles(array_keys($edges[$edge_type]));
|
2012-12-11 23:03:16 +01:00
|
|
|
$view->addProperty(
|
|
|
|
$edge_name,
|
2015-03-30 15:18:54 +02:00
|
|
|
$edge_handles->renderList());
|
2012-12-11 23:03:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-06 20:40:43 +02:00
|
|
|
if ($revisions_commits) {
|
|
|
|
$view->addProperty(
|
|
|
|
pht('Commits'),
|
|
|
|
phutil_implode_html(phutil_tag('br'), $revisions_commits));
|
|
|
|
}
|
|
|
|
|
2014-09-03 21:49:24 +02:00
|
|
|
$view->invokeWillRenderEvent();
|
|
|
|
|
2013-09-24 20:10:46 +02:00
|
|
|
$field_list->appendFieldsToPropertyList(
|
|
|
|
$task,
|
|
|
|
$viewer,
|
|
|
|
$view);
|
|
|
|
|
2013-10-11 16:53:56 +02:00
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildDescriptionView(
|
|
|
|
ManiphestTask $task,
|
|
|
|
PhabricatorMarkupEngine $engine) {
|
|
|
|
|
|
|
|
$section = null;
|
2012-12-11 23:03:16 +01:00
|
|
|
if (strlen($task->getDescription())) {
|
2013-10-11 16:53:56 +02:00
|
|
|
$section = new PHUIPropertyListView();
|
2013-11-04 20:07:51 +01:00
|
|
|
$section->addSectionHeader(
|
|
|
|
pht('Description'),
|
|
|
|
PHUIPropertyListView::ICON_SUMMARY);
|
2013-10-11 16:53:56 +02:00
|
|
|
$section->addTextContent(
|
2013-01-29 03:46:48 +01:00
|
|
|
phutil_tag(
|
2012-12-11 23:03:16 +01:00
|
|
|
'div',
|
|
|
|
array(
|
|
|
|
'class' => 'phabricator-remarkup',
|
|
|
|
),
|
|
|
|
$engine->getOutput($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION)));
|
2012-07-19 05:41:42 +02:00
|
|
|
}
|
2012-12-11 23:03:16 +01:00
|
|
|
|
2013-10-11 16:53:56 +02:00
|
|
|
return $section;
|
2012-07-19 05:41:42 +02:00
|
|
|
}
|
|
|
|
|
2011-02-08 19:53:59 +01:00
|
|
|
}
|